Ejemplo n.º 1
0
static int _update_shadow(const char *forwho, char *towhat)
{
    struct spwd *spwdent = NULL, *stmpent = NULL;
    FILE *pwfile, *opwfile;
    int err = 1;
    int oldmask;

    spwdent = getspnam(forwho);
    if (spwdent == NULL) {
	return PAM_USER_UNKNOWN;
    }
    oldmask = umask(077);
    pwfile = fopen(SH_TMPFILE, "w");
    umask(oldmask);
    if (pwfile == NULL) {
	return PAM_AUTHTOK_ERR;
    }

    opwfile = fopen("/etc/shadow", "r");
    if (opwfile == NULL) {
	fclose(pwfile);
	return PAM_AUTHTOK_ERR;
    }

    chown(SH_TMPFILE, 0, 0);
    chmod(SH_TMPFILE, 0600);
    stmpent = fgetspent(opwfile);
    while (stmpent) {

	if (!strcmp(stmpent->sp_namp, forwho)) {
	    stmpent->sp_pwdp = towhat;
	    stmpent->sp_lstchg = time(NULL) / (60 * 60 * 24);
	    err = 0;
	    D(("Set password %s for %s", stmpent->sp_pwdp, forwho));
	}

	if (putspent(stmpent, pwfile)) {
	    D(("error writing entry to shadow file: %s\n", strerror(errno)));
	    err = 1;
	    break;
	}

	stmpent = fgetspent(opwfile);
    }
    fclose(opwfile);

    if (fclose(pwfile)) {
	D(("error writing entries to shadow file: %s\n", strerror(errno)));
	err = 1;
    }

    if (!err) {
	rename(SH_TMPFILE, "/etc/shadow");
	return PAM_SUCCESS;
    } else {
	unlink(SH_TMPFILE);
	return PAM_AUTHTOK_ERR;
    }
}
Ejemplo n.º 2
0
// Uses fgetspent() instead of getspnam(), to guarantee that the returned user
// is a local user, and not for example from LDAP.
static struct spwd *GetSpEntry(const char *puser)
{
    FILE *fptr = fopen("/etc/shadow", "r");
    if (!fptr)
    {
        Log(LOG_LEVEL_ERR, "Could not open '/etc/shadow': %s", GetErrorStr());
        return NULL;
    }

    struct spwd *spwd_info;
    bool found = false;
    while ((spwd_info = fgetspent(fptr)))
    {
        if (strcmp(puser, spwd_info->sp_namp) == 0)
        {
            found = true;
            break;
        }
    }

    fclose(fptr);

    if (found)
    {
        return spwd_info;
    }
    else
    {
        // Failure to find the user means we just set errno to zero.
        // Perhaps not optimal, but we cannot pass ENOENT, because the fopen might
        // fail for this reason, and that should not be treated the same.
        errno = 0;
        return NULL;
    }
}
Ejemplo n.º 3
0
static VALUE
rb_shadow_fgetspent(VALUE self, VALUE file)
{
  struct spwd *entry;
  VALUE result;

  if( TYPE(file) != T_FILE )
    rb_raise(rb_eTypeError,"argument must be a File.");

  entry = fgetspent(file_ptr(RFILE(file)->fptr));

  if( entry == NULL )
    return Qnil;

  result = rb_struct_new(rb_sPasswdEntry,
		      rb_tainted_str_new2(entry->sp_namp),
		      rb_tainted_str_new2(entry->sp_pwdp),
		      INT2FIX(entry->sp_lstchg),
		      INT2FIX(entry->sp_min),
		      INT2FIX(entry->sp_max),
		      INT2FIX(entry->sp_warn),
		      INT2FIX(entry->sp_inact),
		      INT2FIX(entry->sp_expire),
		      INT2FIX(entry->sp_flag),
		      0);
  return result;
};
Ejemplo n.º 4
0
static VALUE
rb_shadow_fgetspent(VALUE self, VALUE file)
{
    struct spwd *entry;
    VALUE result;

    if( TYPE(file) != T_FILE )
        rb_raise(rb_eTypeError,"argument must be a File.");
    entry = fgetspent( file_ptr( (RFILE(file)->fptr) ) );

    if( entry == NULL )
        return Qnil;

    result = convert_pw_struct( entry );
    return result;
};
Ejemplo n.º 5
0
struct spwd *spwd_find(const char *spwd_path, const char *name) {
	struct spwd *spwd;
	FILE *shdwf;

	if (NULL == (shdwf = fopen(spwd_path, "r"))) {
		return NULL;
	}

	while (NULL != (spwd = fgetspent(shdwf))) {
		if (0 == strcmp(spwd->sp_namp, name)) {
			break;
		}
	}

	fclose(shdwf);

	return spwd;
}
Ejemplo n.º 6
0
GBytes *CacheUtilReadShadowFile(const gchar *path, const gchar *username, GError **error) {
  struct spwd *stmpent = NULL;
  
  FILE *shadowfile = fopen(path, "r");
  if (shadowfile == NULL) {
    g_set_error(error, UTIL_ERROR, UTIL_ERROR_NO_OPEN_FILE, "Failed to open file: %s",  g_strerror(errno));
    return NULL;
  }

  while ((stmpent = fgetspent(shadowfile))) {
    if (!strcmp(stmpent->sp_namp, username)) {
      // Return matching shadow hash value.
      GBytes* hash = g_bytes_new(stmpent->sp_pwdp, strlen(stmpent->sp_pwdp));
      fclose(shadowfile);
      return hash;
    }
  }
  fclose(shadowfile);
  g_set_error(error, UTIL_ERROR, UTIL_ERROR_NO_HASH, "Could not find shadow hash.");
  return NULL;
}
Ejemplo n.º 7
0
PAMH_ARG_DECL(int unix_update_shadow,
	const char *forwho, char *towhat)
{
    struct spwd spwdent, *stmpent = NULL;
    struct stat st;
    FILE *pwfile, *opwfile;
    int err = 0;
    int oldmask;
    int wroteentry = 0;
#ifdef WITH_SELINUX
    security_context_t prev_context=NULL;
#endif

    oldmask = umask(077);

#ifdef WITH_SELINUX
    if (SELINUX_ENABLED) {
      security_context_t shadow_context=NULL;
      if (getfilecon("/etc/shadow",&shadow_context)<0) {
	return PAM_AUTHTOK_ERR;
      };
      if (getfscreatecon(&prev_context)<0) {
	freecon(shadow_context);
	return PAM_AUTHTOK_ERR;
      }
      if (setfscreatecon(shadow_context)) {
	freecon(shadow_context);
	freecon(prev_context);
	return PAM_AUTHTOK_ERR;
      }
      freecon(shadow_context);
    }
#endif
    pwfile = fopen(SH_TMPFILE, "w");
    umask(oldmask);
    if (pwfile == NULL) {
	err = 1;
	goto done;
    }

    opwfile = fopen("/etc/shadow", "r");
    if (opwfile == NULL) {
	fclose(pwfile);
	err = 1;
	goto done;
    }

    if (fstat(fileno(opwfile), &st) == -1) {
	fclose(opwfile);
	fclose(pwfile);
	err = 1;
	goto done;
    }

    if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) {
	fclose(opwfile);
	fclose(pwfile);
	err = 1;
	goto done;
    }
    if (fchmod(fileno(pwfile), st.st_mode) == -1) {
	fclose(opwfile);
	fclose(pwfile);
	err = 1;
	goto done;
    }

    stmpent = fgetspent(opwfile);
    while (stmpent) {

	if (!strcmp(stmpent->sp_namp, forwho)) {
	    stmpent->sp_pwdp = towhat;
	    stmpent->sp_lstchg = time(NULL) / (60 * 60 * 24);
	    if (stmpent->sp_lstchg == 0)
	        stmpent->sp_lstchg = -1; /* Don't request passwort change
					    only because time isn't set yet. */
	    wroteentry = 1;
	    D(("Set password %s for %s", stmpent->sp_pwdp, forwho));
	}

	if (putspent(stmpent, pwfile)) {
	    D(("error writing entry to shadow file: %m"));
	    err = 1;
	    break;
	}

	stmpent = fgetspent(opwfile);
    }

    fclose(opwfile);

    if (!wroteentry && !err) {
	spwdent.sp_namp = forwho;
	spwdent.sp_pwdp = towhat;
	spwdent.sp_lstchg = time(NULL) / (60 * 60 * 24);
	if (spwdent.sp_lstchg == 0)
	    spwdent.sp_lstchg = -1; /* Don't request passwort change
				       only because time isn't set yet. */
	spwdent.sp_min = spwdent.sp_max = spwdent.sp_warn = spwdent.sp_inact =
	    spwdent.sp_expire = -1;
	spwdent.sp_flag = (unsigned long)-1l;
	if (putspent(&spwdent, pwfile)) {
	    D(("error writing entry to shadow file: %m"));
	    err = 1;
	}
    }

    if (fflush(pwfile) || fsync(fileno(pwfile))) {
	D(("fflush or fsync error writing entries to shadow file: %m"));
	err = 1;
    }

    if (fclose(pwfile)) {
	D(("fclose error writing entries to shadow file: %m"));
	err = 1;
    }

 done:
    if (!err) {
	if (!rename(SH_TMPFILE, "/etc/shadow"))
	    pam_syslog(pamh,
		LOG_NOTICE, "password changed for %s", forwho);
	else
	    err = 1;
    }

#ifdef WITH_SELINUX
    if (SELINUX_ENABLED) {
      if (setfscreatecon(prev_context)) {
	err = 1;
      }
      if (prev_context)
	freecon(prev_context);
      prev_context=NULL;
    }
#endif

    if (!err) {
	return PAM_SUCCESS;
    } else {
	unlink(SH_TMPFILE);
	return PAM_AUTHTOK_ERR;
    }
}
Ejemplo n.º 8
0
struct spwd *getspent (void)
{
#ifdef	USE_NIS
	int nis_1_user = 0;
	struct spwd *val;
	char buf[BUFSIZ];
#endif
	if (NULL == shadow) {
		setspent ();
	}

#ifdef	USE_NIS
      again:
	/*
	 * See if we are reading from the local file.
	 */

	if (nis_state == native || nis_state == native2) {

		/*
		 * Get the next entry from the shadow file.  Return NULL
		 * right away if there is none.
		 */

		val = fgetspent (shadow);
		if (NULL == val)
			return 0;

		/*
		 * If this entry began with a NIS escape character, we have
		 * to see if this is just a single user, or if the entire
		 * map is being asked for.
		 */

		if (IS_NISCHAR (val->sp_namp[0])) {
			if (val->sp_namp[1])
				nis_1_user = 1;
			else
				nis_state = start;
		}

		/*
		 * If this isn't a NIS user and this isn't an escape to go
		 * use a NIS map, it must be a regular local user.
		 */

		if (nis_1_user == 0 && nis_state != start)
			return val;

		/*
		 * If this is an escape to use an NIS map, switch over to
		 * that bunch of code.
		 */

		if (nis_state == start)
			goto again;

		/*
		 * NEEDSWORK.  Here we substitute pieces-parts of this entry.
		 */

		return 0;
	} else {
		if (!nis_bound) {
			if (bind_nis ()) {
				nis_state = native2;
				goto again;
			}
		}
		if (nis_state == start) {
			if (yp_first (nis_domain, "shadow.bynam", &nis_key,
			              &nis_keylen, &nis_val, &nis_vallen)) {
				nis_state = native2;
				goto again;
			}
			nis_state = middle;
		} else if (nis_state == middle) {
			if (yp_next (nis_domain, "shadow.bynam", nis_key,
			             nis_keylen, &nis_key, &nis_keylen,
			             &nis_val, &nis_vallen)) {
				nis_state = native2;
				goto again;
			}
		}
		return my_sgetspent (nis_val);
	}
#else
	return (fgetspent (shadow));
#endif
}
Ejemplo n.º 9
0
void
changepasswd(SVCXPRT *transp)
{
	/*
	 * Put these numeric constants into const variables so
	 *   a) they're visible in a debugger
	 *   b) the compiler can play it's cool games with em
	 */
	static const int cryptpwsize = CRYPT_MAXCIPHERTEXTLEN;
	static const int fingersize = FINGERSIZE;
	static const int shellsize = SHELLSIZE;

	struct yppasswd yppwd;
	struct passwd newpw, opwd;
	struct spwd ospwd;
	struct sigaction sa, osa1, osa2, osa3;
	struct stat pwstat, spstat, adjstat;
	char *oldpass_crypt = NULL;

	char newpasswdfile[FILENAME_MAX];
	char newshadowfile[FILENAME_MAX];
	char newadjunctfile[FILENAME_MAX];
	char tmppasswdfile[FILENAME_MAX];
	char tmpshadowfile[FILENAME_MAX];
	char tmpadjunctfile[FILENAME_MAX];
	char pwbuf[NSS_LINELEN_PASSWD], spbuf[NSS_LINELEN_SHADOW];
	char adjbuf[BUFSIZ+1], adjbuf_new[BUFSIZ+1], cmdbuf[BUFSIZ];
	char adj_encrypt[CRYPT_MAXCIPHERTEXTLEN + 1];
	/*
	 * The adj_crypt_* pointers are used to point into adjbuf
	 * NOT adj_encrypt
	 */
	char *adj_crypt_begin, *adj_crypt_end;
	char name[UTUSERLEN + sizeof (":")];
	char *p;

	FILE *opwfp = NULL, *ospfp = NULL, *oadjfp = NULL,
	    *npwfp = NULL, *nspfp = NULL, *nadjfp = NULL;
	int npwfd = -1, nspfd = -1, nadjfd = -1;

	int i, ans, chsh, chpw, chgecos, namelen;
	int gotadjunct = 0, gotshadow = 0, gotpasswd = 0;
	int doneflag = 0, root_on_master = 0;
	pid_t retval;

	time_t now;

	long pwpos = 0, sppos = 0;

	/* Globals :-( */
	extern int single, nogecos, noshell, nopw, mflag, Mstart, Argc;
	extern char **Argv;
	extern char passwd_file[], shadow_file[], adjunct_file[];
	extern int useadjunct;
	extern int useshadow;

	/* Clean out yppwd */
	memset(&yppwd, 0, sizeof (struct yppasswd));

	/* Get the RPC args */
	if (!svc_getargs(transp, xdr_yppasswd, (caddr_t)&yppwd)) {
		svcerr_decode(transp);
		return;
	}

	/* Perform basic validation */
	if (/* (!validstr(yppwd.oldpass, PWSIZE)) || */ /* see PR:nis/38 */
	    (!validstr(yppwd.newpw.pw_passwd, cryptpwsize)) ||
	    (!validstr(yppwd.newpw.pw_name, UTUSERLEN)) ||
	    (!validstr(yppwd.newpw.pw_gecos, fingersize)) ||
	    (!validstr(yppwd.newpw.pw_shell, shellsize))) {
		svcerr_decode(transp);
		return;
	}

	/*
	 * Special case: root on the master server can change other users'
	 * passwords without first entering the old password.  We need to
	 * ensure that this is indeed root on the master server. (bug 1253949)
	 */
	if (strcmp(transp->xp_netid, "ticlts") == 0) {
		svc_local_cred_t cred;
		if (!svc_get_local_cred(transp, &cred)) {
			syslog(LOG_ERR, "yppasswdd: Couldn't get "
			    "local user credentials.\n");
		} else if (cred.ruid == 0)
			root_on_master = 1;
	}

	newpw = yppwd.newpw;
	strcpy(name, newpw.pw_name);
	strcat(name, ":");
	namelen = strlen(name);
	ans = 2;
	chsh = chpw = chgecos = 0;

	/* Get all the filenames straight */
	strcpy(newpasswdfile, passwd_file);
	strcat(newpasswdfile, ".ptmp");
	strcpy(newshadowfile, shadow_file);
	strcat(newshadowfile, ".ptmp");
	strcpy(newadjunctfile, adjunct_file);
	strcat(newadjunctfile, ".ptmp");

	memset(&sa, 0, sizeof (struct sigaction));
	sa.sa_handler = SIG_IGN;
	sigaction(SIGTSTP, &sa, (struct sigaction *)0);
	sigaction(SIGHUP,  &sa, &osa1);
	sigaction(SIGINT,  &sa, &osa2);
	sigaction(SIGQUIT, &sa, &osa3);

	/* Lock, then open the passwd and shadow files */

	if (yplckpwdf() < 0) {
		syslog(LOG_ERR,
		    "yppasswdd: Password file(s) busy. "
		    "Try again later.\n");
		ans = 8;
		goto cleanup;
	}

	if ((opwfp = fopen(passwd_file, "r")) == NULL) {
		syslog(LOG_ERR, "yppasswdd: Could not open %s\n", passwd_file);
		goto cleanup;
	}

	fstat(fileno(opwfp), &pwstat);

	if (useshadow) {
		if ((ospfp = fopen(shadow_file, "r")) == NULL) {
			syslog(LOG_ERR,
			    "yppasswdd: Could not open %s\n", shadow_file);
			goto cleanup;
		}

		fstat(fileno(ospfp), &spstat);
	}

	if (useadjunct) {
		if ((oadjfp = fopen(adjunct_file, "r")) == NULL) {
			syslog(LOG_ERR,
			    "yppasswdd: Could not open %s\n",
			    adjunct_file);
			goto cleanup;
		}

		fstat(fileno(oadjfp), &adjstat);
	}

	/*
	 * Open the new passwd and shadow tmp files,
	 * first with open and then create a FILE * with fdopen()
	 */
	if ((npwfd = open(newpasswdfile, O_WRONLY | O_CREAT | O_EXCL,
	    pwstat.st_mode)) < 0) {
		if (errno == EEXIST) {
			syslog(LOG_WARNING,
			    "yppasswdd: passwd file busy - try again\n");
			ans = 8;
		} else {
			syslog(LOG_ERR, "yppasswdd: %s: %m",
			    newpasswdfile);
			ans = 9;
		}
		goto cleanup;
	}

	fchown(npwfd, pwstat.st_uid, pwstat.st_gid);

	if ((npwfp = fdopen(npwfd, "w")) == NULL) {
		syslog(LOG_ERR,
		    "yppasswdd: fdopen() on %s failed\n", newpasswdfile);
		goto cleanup;
	}

	if (useshadow) {
		if ((nspfd = open(newshadowfile, O_WRONLY | O_CREAT | O_EXCL,
		    spstat.st_mode)) < 0) {
			if (errno == EEXIST) {
				syslog(LOG_WARNING,
				    "yppasswdd: shadow file busy - try "
				    "again\n");
				ans = 8;
			} else {
				syslog(LOG_ERR, "yppasswdd: %s: %m",
				    newshadowfile);
				ans = 9;
			}
			goto cleanup;
		}

		fchown(nspfd, spstat.st_uid, spstat.st_gid);

		if ((nspfp = fdopen(nspfd, "w")) == NULL) {
			syslog(LOG_ERR,
			    "yppasswdd: fdopen() on %s failed\n",
			    newshadowfile);
			goto cleanup;
		}
	}

	if (useadjunct) {
		if ((nadjfd = open(newadjunctfile, O_WRONLY | O_CREAT | O_EXCL,
		    adjstat.st_mode)) < 0) {
			if (errno == EEXIST) {
				syslog(LOG_WARNING,
				    "yppasswdd: adjunct file busy - try "
				    "again\n");
				ans = 8;
			} else {
				syslog(LOG_ERR, "yppasswdd: %s: %m",
				    newadjunctfile);
				ans = 9;
			}
			goto cleanup;
		}

		fchown(nadjfd, adjstat.st_uid, adjstat.st_gid);

		if ((nadjfp = fdopen(nadjfd, "w")) == NULL) {
			syslog(LOG_ERR,
			    "yppasswdd: fdopen() on %s failed\n",
			    newadjunctfile);
			goto cleanup;
		}
	}

	/*
	 * The following code may not seem all that elegant, but my
	 * interpretation of the man pages relating to the passwd and
	 * shadow files would seem to indicate that there is no guarantee
	 * that the entries contained in those files will be in the same
	 * order...
	 *
	 * So here's the high level overview:
	 *
	 *    Loop through the passwd file reading in lines and writing them
	 *    out to the new file UNTIL we get to the correct entry.
	 *    IF we have a shadow file, loop through it reading in lines and
	 *    writing them out to the new file UNTIL we get to the correct
	 *    entry. IF we have an adjunct file, loop through it reading in
	 *    lines and writing them out to the new file UNTIL we get to the
	 *    correct entry.
	 *
	 *    Figure out what's changing, contruct the new passwd, shadow,
	 *    and adjunct entries and spit em out to the temp files.
	 *    At this point, set the done flag and leap back into the loop(s)
	 *    until you're finished with the files and then leap to the
	 *    section that installs the new files.
	 */

loop_in_files:
	/* While we find things in the passwd file */
	while (fgets(pwbuf, NSS_LINELEN_PASSWD, opwfp)) {

		/*
		 * Is this the passwd entry we want?
		 * If not, then write it out to the new passwd temp file
		 * and remember our position.
		 */
		if (doneflag || strncmp(name, pwbuf, namelen)) {
			if (fputs(pwbuf, npwfp) == EOF) {
				syslog(LOG_ERR,
				    "yppasswdd: write to passwd file "
				    "failed.\n");
				goto cleanup;
			}
			pwpos = ftell(opwfp);
			continue;
		}
		gotpasswd = 1;
		break;
	}

	/* no match */
	if (!gotpasswd) {
		syslog(LOG_ERR, "yppasswdd: user %s does not exist\n", name);
		goto cleanup;
	}

	/* While we find things in the shadow file */
	while (useshadow && fgets(spbuf, NSS_LINELEN_SHADOW, ospfp)) {

		/*
		 * Is this the shadow entry that we want?
		 * If not, write it out to the new shadow temp file
		 * and remember our position.
		 */
		if (doneflag || strncmp(name, spbuf, namelen)) {
			if (fputs(spbuf, nspfp) == EOF) {
				syslog(LOG_ERR,
				    "yppasswdd: write to shadow file "
				    "failed.\n");
				goto cleanup;
			}
			sppos = ftell(ospfp);
			continue;
		}
		gotshadow = 1;
		break;
	}

	/* While we find things in the adjunct file */
	while (useadjunct && fgets(adjbuf, BUFSIZ, oadjfp)) {

		/*
		 * is this the adjunct entry that we want?
		 * If not, write it out to the new temp file
		 * and remember our position.
		 */
		if (doneflag || strncmp(name, adjbuf, namelen)) {
			if (fputs(adjbuf, nadjfp) == EOF) {
				syslog(LOG_ERR,
				    "yppasswdd: write to adjunct file "
				    "failed.\n");
				goto cleanup;
			}
			continue;
		}
		gotadjunct = 1;
		break;
	}

	if (doneflag)
		goto install_files;

	if (useshadow && !gotshadow) {
		syslog(LOG_ERR, "yppasswdd: no passwd in shadow for %s\n",
		    newpw.pw_name);
		ans = 4;
		goto cleanup;
	}
	if (useadjunct && !gotadjunct) {
		syslog(LOG_ERR, "yppasswdd: no passwd in adjunct for %s\n",
		    newpw.pw_name);
		ans = 4;
		goto cleanup;
	}

	/*
	 * Now that we've read in the correct passwd AND
	 * shadow lines, we'll rewind to the beginning of
	 * those lines and let the fget*ent() calls do
	 * the work.  Since we are only working with the
	 * first two fields of the adjunct entry, leave
	 * it as a char array.
	 */
	fseek(opwfp, pwpos, SEEK_SET);
	opwd  = *fgetpwent(opwfp);

	if (useshadow) {
		fseek(ospfp, sppos, SEEK_SET);
		ospwd = *fgetspent(ospfp);
	}

	oldpass_crypt = cryptoldpasswd(yppwd.oldpass, newpw.pw_passwd,
	    newpw.pw_name);
	if (oldpass_crypt == NULL) {
		ans = 3;
		goto cleanup;
	}
	p = newpw.pw_passwd;
	if ((!nopw) &&
	    p && *p &&
	    !((*p++ == '#') && (*p++ == '#') &&
	    (strcmp(p, opwd.pw_name) == 0)) &&
	    (strcmp(oldpass_crypt, newpw.pw_passwd) != 0))
		chpw = 1;
	oldpass_crypt = NULL;

	if ((!noshell) && (strcmp(opwd.pw_shell, newpw.pw_shell) != 0)) {
		if (single)
			chpw = 0;
		chsh = 1;
	}

	if ((!nogecos) && (strcmp(opwd.pw_gecos, newpw.pw_gecos) != 0)) {
		if (single) {
			chpw = 0;
			chsh = 0;
		}
		chgecos = 1;
	}

	if (!(chpw + chsh + chgecos)) {
		syslog(LOG_NOTICE, "yppasswdd: no change for %s\n",
		    newpw.pw_name);
		ans = 3;
		goto cleanup;
	}

	if (useshadow && !root_on_master) {
		oldpass_crypt = cryptoldpasswd(yppwd.oldpass, ospwd.sp_pwdp,
		    newpw.pw_name);
		if (oldpass_crypt == NULL)
			goto cleanup;
		if (ospwd.sp_pwdp && *ospwd.sp_pwdp &&
		    (strcmp(oldpass_crypt, ospwd.sp_pwdp) != 0)) {

			syslog(LOG_NOTICE, "yppasswdd: passwd incorrect\n",
			    newpw.pw_name);
			ans = 7;
			goto cleanup;
		}
	} else if (useadjunct) {
		/*
		 * Clear the adj_encrypt array.  Extract the encrypted passwd
		 * into adj_encrypt by setting adj_crypt_begin and
		 * adj_crypt_end to point at the first character of the
		 * encrypted passwd and the first character following the
		 * encrypted passwd in adjbuf, respectively, and copy the
		 * stuff between (there may not be anything) into adj_ecrypt.
		 * Then, check that adj_encrypt contains something and that
		 * the old passwd is correct.
		 */
		memset(adj_encrypt, 0, sizeof (adj_encrypt));
		adj_crypt_begin = adjbuf + namelen;
		adj_crypt_end = strchr(adj_crypt_begin, ':');
		strncpy(adj_encrypt, adj_crypt_begin,
		    adj_crypt_end - adj_crypt_begin);
		oldpass_crypt = cryptoldpasswd(yppwd.oldpass, adj_encrypt,
		    newpw.pw_name);
		if (oldpass_crypt == NULL)
			goto cleanup;
		if (!root_on_master && *adj_encrypt &&
		    (strcmp(oldpass_crypt, adj_encrypt) != 0)) {

			syslog(LOG_NOTICE, "yppasswdd: passwd incorrect\n",
			    newpw.pw_name);
			ans = 7;
			goto cleanup;
		}
	} else {
		oldpass_crypt = cryptoldpasswd(yppwd.oldpass, opwd.pw_passwd,
		    newpw.pw_name);
		if (oldpass_crypt == NULL)
			goto cleanup;
		if (!root_on_master && opwd.pw_passwd && *opwd.pw_passwd &&
		    (strcmp(oldpass_crypt, opwd.pw_passwd) != 0)) {

			syslog(LOG_NOTICE, "yppasswdd: passwd incorrect\n",
			    newpw.pw_name);
			ans = 7;
			goto cleanup;
		}
	}

#ifdef DEBUG
	printf("%d %d %d\n", chsh, chgecos, chpw);

	printf("%s %s %s\n",
	    yppwd.newpw.pw_shell,
	    yppwd.newpw.pw_gecos,
	    yppwd.newpw.pw_passwd);

	printf("%s %s %s\n",
	    opwd.pw_shell,
	    opwd.pw_gecos,
	    ospwd.sp_pwdp);
#endif

	if (chsh &&
	    !validloginshell(opwd.pw_shell, newpw.pw_shell, root_on_master)) {
		goto cleanup;
	}

	/* security hole fix from original source */
	for (p = newpw.pw_name; (*p != '\0'); p++)
		if ((*p == ':') || !(isprint(*p)))
			*p = '$';	/* you lose buckwheat */
	for (p = newpw.pw_passwd; (*p != '\0'); p++)
		if ((*p == ':') || !(isprint(*p)))
			*p = '$';	/* you lose buckwheat */

	if (chgecos)
		opwd.pw_gecos = newpw.pw_gecos;

	if (chsh)
		opwd.pw_shell = newpw.pw_shell;

	/*
	 * If we're changing the shell or gecos fields and we're
	 * using a shadow or adjunct file or not changing the passwd
	 * then go ahead and update the passwd file.  The case where
	 * the passwd is being changed and we are not using a shadow
	 * or adjunct file is handled later.
	 */
	if ((chsh || chgecos) && (useshadow || useadjunct || !chpw) &&
	    putpwent(&opwd, npwfp)) {

		syslog(LOG_ERR, "yppasswdd: putpwent failed: %s\n",
		    passwd_file);
		goto cleanup;
	}

	if (chpw) {
		if (useshadow) {
			ospwd.sp_pwdp = newpw.pw_passwd;
			now = DAY_NOW;
			/* password aging - bug for bug compatibility */
			if (ospwd.sp_max != -1) {
				if (now < ospwd.sp_lstchg + ospwd.sp_min) {
					syslog(LOG_ERR,
					    "yppasswdd: Sorry: < %ld days "
					    "since the last change.\n",
					    ospwd.sp_min);
					goto cleanup;
				}
			}
			ospwd.sp_lstchg = now;
			if (putspent(&ospwd, nspfp)) {
				syslog(LOG_ERR,
				    "yppasswdd: putspent failed: %s\n",
				    shadow_file);
				goto cleanup;
			}
		} else if (useadjunct) {
			sprintf(adjbuf_new,
			    "%s%s%s", name, newpw.pw_passwd, adj_crypt_end);
			if (fputs(adjbuf_new, nadjfp) == EOF) {
				syslog(LOG_ERR,
				    "yppasswdd: write to adjunct failed: %s\n",
				    adjunct_file);
				goto cleanup;
			}
		} else {
			opwd.pw_passwd = newpw.pw_passwd;
			if (putpwent(&opwd, npwfp)) {
				syslog(LOG_ERR,
				    "yppasswdd: putpwent failed: %s\n",
				    passwd_file);
				goto cleanup;
			}
		}
	}

	if (!doneflag) {
		doneflag = 1;
		goto loop_in_files;
	}

install_files:
	/*
	 * Critical section, nothing special needs to be done since we
	 * hold exclusive access to the *.ptmp files
	 */
	fflush(npwfp);
	if (useshadow)
		fflush(nspfp);
	if (useadjunct)
		fflush(nadjfp);

	strcpy(tmppasswdfile, passwd_file);
	strcat(tmppasswdfile, "-");
	if (useshadow) {
		strcpy(tmpshadowfile, shadow_file);
		strcat(tmpshadowfile, "-");
	}
	if (useadjunct) {
		strcpy(tmpadjunctfile, adjunct_file);
		strcat(tmpadjunctfile, "-");
	}

	if ((!useshadow && !useadjunct) || (chsh || chgecos)) {
		if (rename(passwd_file, tmppasswdfile) < 0) {
			syslog(LOG_CRIT, "yppasswdd: failed to backup "
			    "passwd file: %m");
			goto cleanup;
		} else {
			if (rename(newpasswdfile, passwd_file) < 0) {
				syslog(LOG_CRIT,
				    "yppasswdd: failed to mv passwd: %m");
				if (rename(tmppasswdfile, passwd_file) < 0) {
					syslog(LOG_CRIT,
					    "yppasswdd: failed to restore "
					    "backup of passwd file: %m");
				}
				goto cleanup;
			}
		}
	}

	if (useshadow && chpw) {
		if (rename(shadow_file, tmpshadowfile) < 0) {
			syslog(LOG_CRIT, "yppasswdd: failed to back up "
			    "shadow file: %m");
			if (rename(tmppasswdfile, passwd_file) < 0) {
				syslog(LOG_CRIT,
				    "yppasswdd: failed to restore "
				    "backup of passwd file: %m");
			}
			goto cleanup;
		} else {
			if (rename(newshadowfile, shadow_file) < 0) {
				syslog(LOG_CRIT,
				    "yppasswdd: failed to mv shadow: %m");
				if (rename(tmpshadowfile, shadow_file) < 0) {
					syslog(LOG_CRIT,
					    "yppasswdd: failed to restore "
					    "backup of shadow file: %m");
				}
				if (rename(tmppasswdfile, passwd_file) < 0) {
					syslog(LOG_CRIT,
					    "yppasswdd: failed to restore "
					    "backup of passwd file: %m");
				}
				goto cleanup;
			}
		}
	} else if (useadjunct && chpw) {
		if (rename(adjunct_file, tmpadjunctfile) < 0) {
			syslog(LOG_CRIT, "yppasswdd: failed to back up "
			    "adjunct file: %m");
			if (rename(tmppasswdfile, passwd_file) < 0) {
				syslog(LOG_CRIT,
				    "yppasswdd: failed to restore backup "
				    "of passwd: %m");
			}
			goto cleanup;
		} else {
			if (rename(newadjunctfile, adjunct_file) < 0) {
				syslog(LOG_CRIT,
				    "yppassdd: failed to mv adjunct: %m");
				if (rename(tmppasswdfile, passwd_file) < 0) {
					syslog(LOG_CRIT,
					    "yppasswdd: failed to restore "
					    "backup of passwd file: %m");
				}
				if (rename(tmpadjunctfile, adjunct_file) < 0) {
					syslog(LOG_CRIT,
					    "yppasswdd: failed to restore "
					    "backup of adjunct file: %m");
				}
				goto cleanup;
			}
		}
	}

	if (doneflag)
		ans = 0;
	/* End critical section */

	/*
	 *  Here we have come only after the new files have been successfully
	 * renamed to original files. At this point, the temp files would still
	 * be existing we need to remove them from the /etc directory
	 */
	unlink(tmppasswdfile);
	if (useshadow)
		unlink(tmpshadowfile);
	if (useadjunct)
		unlink(tmpadjunctfile);

cleanup:

	/* If we don't have opwfp, then we didn't do anything */
	if (opwfp) {
		fclose(opwfp);

		if (ospfp) {
			fclose(ospfp);
		}

		if (oadjfp) {
			fclose(oadjfp);
		}

		unlink(newpasswdfile);
		/* These tests are cheaper than failing syscalls */
		if (useshadow)
			unlink(newshadowfile);
		if (useadjunct)
			unlink(newadjunctfile);

		if (npwfp) {
			fclose(npwfp);

			if (nspfp) {
				fclose(nspfp);
			}
			if (nadjfp) {
				fclose(nadjfp);
			}
		}
	}

	ypulckpwdf();

	if (doneflag && mflag) {
		retval = fork();
		if (retval < 0) {
			syslog(LOG_ERR, "yppasswdd: Fork failed %m");
		} else if (retval == 0) {
			strcpy(cmdbuf, "/usr/ccs/bin/make");
			for (i = Mstart + 1; i < Argc; i++) {
				strcat(cmdbuf, " ");
				strcat(cmdbuf, Argv[i]);
			}

#ifdef DEBUG
			syslog(LOG_ERR, "yppasswdd: about to "
			    "execute %s\n", cmdbuf);
#else
			if (yplckpwdf() < 0) {
				syslog(LOG_ERR, "yppasswdd: Couldn't get the "
				    "lock to update the maps");
			} else {
				setpgrp();
				system(cmdbuf);
				ypulckpwdf();
			}
#endif
			exit(0);
		}
	}

	sigaction(SIGHUP,  &osa1, (struct sigaction *)0);
	sigaction(SIGINT,  &osa2, (struct sigaction *)0);
	sigaction(SIGQUIT, &osa3, (struct sigaction *)0);

	if (!svc_sendreply(transp, xdr_int, (char *)&ans))
		syslog(LOG_WARNING,
		    "yppasswdd: couldn\'t reply to RPC call\n");
}
Ejemplo n.º 10
0
bool KUserFiles::loadpwd()
{
  passwd *p;
  KU::KUser *tmpKU = 0;
  struct stat st;
  QString filename;
  QString passwd_filename;
  QString nispasswd_filename;
  int rc = 0;
  int passwd_errno = 0;
  int nispasswd_errno = 0;
  char processing_file = '\0';
  #define P_PASSWD    0x01
  #define P_NISPASSWD 0x02
  #define MAXFILES 2

  // Read KUser configuration

  passwd_filename = mCfg->passwdsrc();
  nispasswd_filename = mCfg->nispasswdsrc();

  // Handle unconfigured environments

  if(passwd_filename.isEmpty() && nispasswd_filename.isEmpty()) {
    mCfg->setPasswdsrc( PASSWORD_FILE );
    mCfg->setGroupsrc( GROUP_FILE );
    passwd_filename = mCfg->passwdsrc();
    KMessageBox::error( 0, i18n("KUser sources were not configured.\nLocal passwd source set to %1\nLocal group source set to %2.").arg(mCfg->passwdsrc().arg(mCfg->groupsrc())) );
  }

  if(!passwd_filename.isEmpty()) {
    processing_file = processing_file | P_PASSWD;
    filename.append(passwd_filename);
  }

  // Start reading passwd file(s)

  for(int i = 0; i < MAXFILES; i++) {
    rc = stat(QFile::encodeName(filename), &st);
    if(rc != 0) {
      KMessageBox::error( 0, i18n("Stat call on file %1 failed: %2\nCheck KUser settings.").arg(filename).arg(QString::fromLocal8Bit(strerror(errno))) );
      if( (processing_file & P_PASSWD) != 0 ) {
        passwd_errno = errno;
        if(!nispasswd_filename.isEmpty()) {
          processing_file = processing_file & ~P_PASSWD;
          processing_file = processing_file | P_NISPASSWD;
          filename.truncate(0);
          filename.append(nispasswd_filename);
        }
        continue;
      }
      else{
        nispasswd_errno = errno;
        break;
      }
    }

    pwd_mode = st.st_mode & 0666;
    pwd_uid = st.st_uid;
    pwd_gid = st.st_gid;

    // We are reading our configuration specified passwd file
    QString tmp;

#ifdef HAVE_FGETPWENT
    FILE *fpwd = fopen(QFile::encodeName(filename), "r");
    if(fpwd == NULL) {
      KMessageBox::error( 0, i18n("Error opening %1 for reading.").arg(filename) );
      return FALSE;
    }

    while ((p = fgetpwent(fpwd)) != NULL) {
#else
    setpwent(); //This should be enough for BSDs
    while ((p = getpwent()) != NULL) {
#endif
      tmpKU = new KU::KUser();
      tmpKU->setCaps( KU::KUser::Cap_POSIX );
      tmpKU->setUID(p->pw_uid);
      tmpKU->setGID(p->pw_gid);
      tmpKU->setName(QString::fromLocal8Bit(p->pw_name));
      tmp  = QString::fromLocal8Bit( p->pw_passwd );
      if ( tmp != "x" && tmp != "*" && !tmp.startsWith("!") )
        tmpKU->setDisabled( false );
      else
        tmpKU->setDisabled( true );
      if ( tmp.startsWith("!") ) tmp.remove(0, 1);
      tmpKU->setPwd( tmp );
      tmpKU->setHomeDir(QString::fromLocal8Bit(p->pw_dir));
      tmpKU->setShell(QString::fromLocal8Bit(p->pw_shell));
#if defined(__FreeBSD__) || defined(__bsdi__)
      tmpKU->setClass(QString::fromLatin1(p->pw_class));
      tmpKU->setLastChange(p->pw_change);
      tmpKU->setExpire(p->pw_expire);
#endif

      if ((p->pw_gecos != 0) && (p->pw_gecos[0] != 0))
        fillGecos(tmpKU, p->pw_gecos);
      mUsers.append(tmpKU);
    }

    // End reading passwd_filename

#ifdef HAVE_FGETPWENT
    fclose(fpwd);
#else
    endpwent();
#endif
    if((!nispasswd_filename.isEmpty()) && (nispasswd_filename != passwd_filename)) {
      processing_file = processing_file & ~P_PASSWD;
      processing_file = processing_file | P_NISPASSWD;
      filename.truncate(0);
      filename.append(nispasswd_filename);
    }
    else
      break;

  } // end of processing files, for loop

  if( (passwd_errno == 0) && (nispasswd_errno == 0) )
    return (TRUE);
  if( (passwd_errno != 0) && (nispasswd_errno != 0) )
    return (FALSE);
  else
    return(TRUE);
}

// Load shadow passwords

bool KUserFiles::loadsdw()
{
#ifdef HAVE_SHADOW
  QString shadow_file,tmp;
  struct spwd *spw;
  KU::KUser *up = NULL;
  struct stat st;

  shadow_file = mCfg->shadowsrc();
  if ( shadow_file.isEmpty() )
    return TRUE;

  stat( QFile::encodeName(shadow_file), &st);
  sdw_mode = st.st_mode & 0666;
  sdw_uid = st.st_uid;
  sdw_gid = st.st_gid;

#ifdef HAVE_FGETSPENT
  FILE *f;
  kdDebug() << "open shadow file: " << shadow_file << endl;
  if ((f = fopen( QFile::encodeName(shadow_file), "r")) == NULL) {
    KMessageBox::error( 0, i18n("Error opening %1 for reading.").arg(shadow_file) );
    caps &= ~Cap_Shadow;
    return TRUE;
  }
  while ((spw = fgetspent( f ))) {     // read a shadow password structure
#else
  setspent();
  while ((spw = getspent())) {     // read a shadow password structure
#endif

    kdDebug() << "shadow entry: " << spw->sp_namp << endl;
    if ((up = lookup(QString::fromLocal8Bit(spw->sp_namp))) == NULL) {
      KMessageBox::error( 0, i18n("No /etc/passwd entry for %1.\nEntry will be removed at the next `Save'-operation.").arg(QString::fromLocal8Bit(spw->sp_namp)) );
      continue;
    }

    tmp = QString::fromLocal8Bit( spw->sp_pwdp );
    if ( tmp.startsWith("!!") || tmp == "*" ) {
      up->setDisabled( true );
      tmp.remove( 0, 2 );
    } else
      up->setDisabled( false );

    up->setSPwd( tmp );        // cp the encrypted pwd
    up->setLastChange( daysToTime( spw->sp_lstchg ) );
    up->setMin(spw->sp_min);
    up->setMax(spw->sp_max);
#ifndef _SCO_DS
    up->setWarn(spw->sp_warn);
    up->setInactive(spw->sp_inact);
    up->setExpire( daysToTime( spw->sp_expire ) );
    up->setFlag(spw->sp_flag);
#endif
  }

#ifdef HAVE_FGETSPENT
  fclose(f);
#else
  endspent();
#endif

#endif // HAVE_SHADOW
  return TRUE;
}

// Save password file

#define escstr(a,b) tmp2 = user->a(); \
                    tmp2.replace(':',"_"); \
                    tmp2.replace(',',"_"); \
                    user->b( tmp2 );


bool KUserFiles::savepwd()
{
  FILE *passwd_fd = NULL;
  FILE *nispasswd_fd = NULL;
  uid_t minuid = 0;
  int nis_users_written = 0;
  uid_t tmp_uid = 0;
  QString s;
  QString s1;
  QString tmp, tmp2;
  QString passwd_filename;
  QString nispasswd_filename;


  char errors_found = '\0';
    #define NOMINUID    0x01
    #define NONISPASSWD 0x02

  // Read KUser configuration info

  passwd_filename = mCfg->passwdsrc();
  nispasswd_filename = mCfg->nispasswdsrc();
  QString new_passwd_filename =
    passwd_filename + QString::fromLatin1(KU_CREATE_EXT);
  QString new_nispasswd_filename =
    nispasswd_filename+QString::fromLatin1(KU_CREATE_EXT);

  if( nispasswd_filename != passwd_filename ) {
    minuid = mCfg->nisminuid();
  }

  // Backup file(s)

  if(!passwd_filename.isEmpty()) {
    if (!pw_backuped) {
      if (!backup(passwd_filename)) return FALSE;
      pw_backuped = TRUE;
    }
  }
  if(!nispasswd_filename.isEmpty() &&
    (nispasswd_filename != passwd_filename)) {
    if (!pn_backuped) {
      if (!backup(nispasswd_filename)) return FALSE;
      pn_backuped = TRUE;
    }
  }

  // Open file(s)

  if(!passwd_filename.isEmpty()) {
    if ((passwd_fd =
      fopen(QFile::encodeName(new_passwd_filename),"w")) == NULL)
        KMessageBox::error( 0, i18n("Error opening %1 for writing.").arg(passwd_filename) );
  }

  if(!nispasswd_filename.isEmpty() && (nispasswd_filename != passwd_filename)){
    if ((nispasswd_fd =
      fopen(QFile::encodeName(new_nispasswd_filename),"w")) == NULL)
        KMessageBox::error( 0, i18n("Error opening %1 for writing.").arg(nispasswd_filename) );
  }

  QPtrListIterator<KU::KUser> it( mUsers );
  KU::KUser *user;
  bool addok = false;
  user = (*it);
  while (true) {
    if ( user == 0 ) {
      if ( addok ) break;
      it = QPtrListIterator<KU::KUser> ( mAdd );
      user = (*it);
      addok = true;
      if ( user == 0 ) break;
    };
    if ( mDel.containsRef( user ) ) {
      ++it;
      user = (*it);
      continue;
    }
    if ( mMod.contains( user ) ) user = &( mMod[ user ] );

    tmp_uid = user->getUID();
    if ( caps & Cap_Shadow )
      tmp = "x";
    else {
      tmp = user->getPwd();
      if ( user->getDisabled() && tmp != "x" && tmp != "*" )
        tmp = "!" + tmp;
    }

    escstr( getName, setName );
    escstr( getHomeDir, setHomeDir );
    escstr( getShell, setShell );
    escstr( getName, setName );
    escstr( getFullName, setFullName );
#if defined(__FreeBSD__) || defined(__bsdi__)
    escstr( getClass, setClass );
    escstr( getOffice, setOffice );
    escstr( getWorkPhone, setWorkPhone );
    escstr( getHomePhone, setHomePhone );
    s =
      user->getName() + ":" +
      tmp + ":" +
      QString::number( user->getUID() ) + ":" +
      QString::number( user->getGID() ) + ":" +
      user->getClass() + ":" +
      QString::number( user->getLastChange() ) + ":" +
      QString::number( user->getExpire() ) + ":";

    s1 =
      user->getFullName() + "," +
      user->getOffice() + "," +
      user->getWorkPhone() + "," +
      user->getHomePhone();
#else
    escstr( getOffice1, setOffice1 );
    escstr( getOffice2, setOffice2 );
    escstr( getAddress, setAddress );
    s =
      user->getName() + ":" +
      tmp + ":" +
      QString::number( user->getUID() ) + ":" +
      QString::number( user->getGID() ) + ":";

    s1 =
      user->getFullName() + "," +
      user->getOffice1() + "," +
      user->getOffice2() + "," +
      user->getAddress();

#endif
    for (int j=(s1.length()-1); j>=0; j--) {
      if (s1[j] != ',')
        break;
      s1.truncate(j);
    }

    s += s1 + ":" +
      user->getHomeDir() + ":" +
      user->getShell() + "\n";

    if( (nispasswd_fd != 0) && (minuid != 0) ) {
      if (minuid <= tmp_uid) {
        fputs(s.local8Bit().data(), nispasswd_fd);
        nis_users_written++;
        ++it;
        user = (*it);
        continue;
      }
    }

    if( (nispasswd_fd != 0) && (minuid == 0) ) {
      errors_found = errors_found | NOMINUID;
    }

    if( (nispasswd_fd == 0) && (minuid != 0) ) {
      errors_found = errors_found | NONISPASSWD;
    }
    kdDebug() << s << endl;
    fputs(s.local8Bit().data(), passwd_fd);

    ++it;
    user = (*it);
  }

  if(passwd_fd) {
    fclose(passwd_fd);
    chmod(QFile::encodeName(new_passwd_filename), pwd_mode);
    chown(QFile::encodeName(new_passwd_filename), pwd_uid, pwd_gid);
    rename(QFile::encodeName(new_passwd_filename),
      QFile::encodeName(passwd_filename));
  }

  if(nispasswd_fd) {
    fclose(nispasswd_fd);
    chmod(QFile::encodeName(new_nispasswd_filename), pwd_mode);
    chown(QFile::encodeName(new_nispasswd_filename), pwd_uid, pwd_gid);
    rename(QFile::encodeName(new_nispasswd_filename),
      QFile::encodeName(nispasswd_filename));
  }

  if( (errors_found & NOMINUID) != 0 ) {
    KMessageBox::error( 0, i18n("Unable to process NIS passwd file without a minimum UID specified.\nPlease update KUser settings (Files).") );
  }

  if( (errors_found & NONISPASSWD) != 0 ) {
    KMessageBox::error( 0, i18n("Specifying NIS minimum UID requires NIS file(s).\nPlease update KUser settings (Files).") );
  }

  // need to run a utility program to build /etc/passwd, /etc/pwd.db
  // and /etc/spwd.db from /etc/master.passwd
#if defined(__FreeBSD__) || defined(__bsdi__)
  if (system(PWMKDB) != 0) {
    KMessageBox::error( 0, i18n("Unable to build password database.") );
    return FALSE;
  }
#else
  if( (nis_users_written > 0) || (nispasswd_filename == passwd_filename) ) {
    if (system(PWMKDB) != 0) {
      KMessageBox::error( 0, i18n("Unable to build password databases.") );
      return FALSE;
    }
  }
#endif

  return TRUE;
}
Ejemplo n.º 11
0
/* getspent - get a (struct spwd *) from the current shadow file */
struct spwd *getspent(void)
{
	if (!shadow)
		setspent();
	return (fgetspent(shadow));
}