summaryrefslogtreecommitdiffstats
path: root/login-utils/setpwnam.c
diff options
context:
space:
mode:
Diffstat (limited to 'login-utils/setpwnam.c')
-rw-r--r--login-utils/setpwnam.c266
1 files changed, 119 insertions, 147 deletions
diff --git a/login-utils/setpwnam.c b/login-utils/setpwnam.c
index 8a01c6ec5..1f1067cf1 100644
--- a/login-utils/setpwnam.c
+++ b/login-utils/setpwnam.c
@@ -8,6 +8,11 @@
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
+ * Edited 11/10/96 (DD/MM/YY ;-) by Nicolai Langfeldt (janl@math.uio.no)
+ * to read /etc/passwd directly so that passwd, chsh and chfn can work
+ * on machines that run NIS (né YP). Changes will not be made to
+ * usernames starting with +.
+ *
* This file is distributed with no warranty.
*
* Usage:
@@ -17,15 +22,25 @@
* 2) edit the fields you want to edit.
* 3) call setpwnam() with the edited struct passwd.
*
- * You should never directly read from or write to /etc/passwd.
- * All user database queries should be directed through
- * getpwnam() and setpwnam().
+ * A _normal user_ program should never directly manipulate
+ * /etc/passwd but use getpwnam() and (family, as well as)
+ * setpwnam().
+ *
+ * But, setpwnam was made to _edit_ the password file. For use by
+ * chfn, chsh and passwd. _I_ _HAVE_ to read and write /etc/passwd
+ * directly. Let those who say nay be forever silent and think about
+ * how getpwnam (and family) works on a machine running YP.
+ *
+ * Added checks for failure of malloc() and removed error reporting
+ * to stderr, this is a library function and should not print on the
+ * screen, but return appropriate error codes.
+ * 27-Jan-97 - poe@daimi.aau.dk
*
* Thanks to "two guys named Ian".
- */
-/* $Author: faith $
- * $Revision: 1.5 $
- * $Date: 1995/10/12 14:46:36 $
+ *
+ * $Author: poer $
+ * $Revision: 1.13 $
+ * $Date: 1997/06/23 08:26:29 $
*/
#undef DEBUG
@@ -43,207 +58,164 @@
#include <errno.h>
#include <signal.h>
#include <sys/resource.h>
-#ifdef BSD43
-#include <sys/file.h>
-#endif
+#include <sys/stat.h>
#include <paths.h>
-#include "pathnames.h"
-
-extern int errno;
+#include "setpwnam.h"
-typedef int boolean;
-#define false 0
-#define true 1
-
-#ifndef DEBUG
-#define PASSWD_FILE _PATH_PASSWD
-#define PTMP_FILE _PATH_PTMP
-#define PTMPTMP_FILE _PATH_PTMPTMP
-#else
-#define PASSWD_FILE "/tmp/passwd"
-#define PTMP_FILE "/tmp/ptmp"
-#define PTMPTMP_FILE "/tmp/ptmptmp"
-#endif
-
-static int copy_pwd (struct passwd *src, struct passwd *dest);
-static char *xstrdup (char *str);
static void pw_init(void);
/*
* setpwnam () --
* takes a struct passwd in which every field is filled in and valid.
- * If the given username exists in the passwd file, his entry is
+ * If the given username exists in the passwd file, the entry is
* replaced with the given entry.
*/
-int setpwnam (struct passwd *pwd)
+int
+setpwnam (struct passwd *pwd)
{
- FILE *fp;
+ FILE *fp = NULL, *pwf = NULL;
int x, save_errno, fd, ret;
- struct passwd *entry;
boolean found;
- struct passwd spwd;
int oldumask;
+ int namelen;
+ int buflen = 256;
+ int contlen;
+ char *linebuf = malloc(buflen);
- /* getpwent() returns a pointer to a static buffer.
- * "pwd" might have some from getpwent(), so we have to copy it to
- * some other buffer before calling getpwent().
- */
- if (copy_pwd (pwd, &spwd) < 0)
- return (-1);
+ if (!linebuf) return -1;
oldumask = umask(0); /* Create with exact permissions */
+
pw_init();
/* sanity check */
for (x = 0; x < 3; x++) {
- if (x > 0) sleep (1);
- fd = open (PTMPTMP_FILE, O_WRONLY|O_CREAT, 0644);
- if(fd == -1) {
- perror(PTMPTMP_FILE);
+ if (x > 0) sleep(1);
+ fd = open(PTMPTMP_FILE, O_WRONLY|O_CREAT, 0644);
+ if (fd == -1) {
umask(oldumask);
- return (-1);
+ return -1;
}
ret = link(PTMPTMP_FILE, PTMP_FILE);
unlink(PTMPTMP_FILE);
- if(ret == -1)
+ if (ret == -1)
close(fd);
else
break;
}
-
umask(oldumask);
- if (ret == -1) return (-1);
+ if (ret == -1) return -1;
/* ptmp should be owned by root.root or root.wheel */
- if (chown (PTMP_FILE, (uid_t) 0, (gid_t) 0) < 0)
- perror ("chown");
+ if (chown(PTMP_FILE, (uid_t) 0, (gid_t) 0) < 0) return -1;
/* open ptmp for writing and passwd for reading */
- fp = fdopen (fd, "w");
- if (! fp) goto fail;
+ fp = fdopen(fd, "w");
+ if (!fp) goto fail;
- setpwent ();
+ pwf = fopen(PASSWD_FILE, "r");
+ if (!pwf) goto fail;
+
+ namelen = strlen(pwd->pw_name);
/* parse the passwd file */
found = false;
- while ((entry = getpwent ()) != NULL) {
- if (! strcmp (spwd.pw_name, entry->pw_name)) {
- entry = &spwd;
- found = true;
- }
- if (putpwent (entry, fp) < 0) goto fail;
+ /* Do you wonder why I don't use getpwent? Read comments at top of file */
+ while (fgets(linebuf, buflen, pwf) != NULL) {
+ contlen = strlen(linebuf);
+ while (linebuf[contlen-1] != '\n' && !feof(pwf)) {
+ /* Extend input buffer if it failed getting the whole line */
+
+ /* So now we double the buffer size */
+ buflen *= 2;
+
+ linebuf = realloc(linebuf, buflen);
+ if (linebuf == NULL) goto fail;
+
+ /* And fill the rest of the buffer */
+ if (fgets(&linebuf[contlen], buflen/2, pwf) == NULL) break;
+ contlen = strlen(linebuf);
+
+ /* That was a lot of work for nothing. Gimme perl! */
+ }
+
+ /* Is this the username we were sent to change? */
+ if (!found && linebuf[namelen] == ':' &&
+ !strncmp(linebuf, pwd->pw_name, namelen)) {
+ /* Yes! So go forth in the name of the Lord and change it! */
+ if (putpwent(pwd, fp) < 0) goto fail;
+ found = true;
+ continue;
+ }
+ /* Nothing in particular happened, copy input to output */
+ fputs(linebuf, fp);
}
- if (fclose (fp) < 0) goto fail;
+
+ if (fclose(fp) < 0) goto fail;
+ fp = NULL;
close (fd);
- endpwent ();
+ fd = -1;
+ fclose (pwf); /* I don't think I want to know if this failed */
+ pwf = NULL;
- if (! found) {
+ if (!found) {
errno = ENOENT; /* give me something better */
goto fail;
}
/* we don't care if we can't remove the backup file */
- unlink (PASSWD_FILE".OLD");
+ unlink(PASSWD_FILE".OLD");
/* we don't care if we can't create the backup file */
- link (PASSWD_FILE, PASSWD_FILE".OLD");
+ link(PASSWD_FILE, PASSWD_FILE".OLD");
/* we DO care if we can't rename to the passwd file */
- if (rename (PTMP_FILE, PASSWD_FILE) < 0)
+ if(rename(PTMP_FILE, PASSWD_FILE) < 0)
goto fail;
/* finally: success */
return 0;
- fail:
+fail:
save_errno = errno;
- if (fp) fclose (fp);
+ if (fp != NULL) fclose (fp);
+ if (pwf != NULL) fclose(pwf);
if (fd >= 0) close (fd);
- endpwent ();
- unlink (PTMP_FILE);
+ if (linebuf != NULL) free(linebuf);
+ unlink(PTMP_FILE);
errno = save_errno;
- return (-1);
+ return -1;
}
-#define memzero(ptr, size) memset((char *) ptr, 0, size)
-static int failed;
-
-static int copy_pwd (struct passwd *src, struct passwd *dest)
-{
- /* this routine destroys abstraction barriers. it's not portable
- * across systems, or even across different versions of the C library
- * on a given system. it's dangerous and evil and wrong and I dispise
- * getpwent() for forcing me to write this.
- */
- failed = 0;
- memzero (dest, sizeof (struct passwd));
- dest->pw_name = xstrdup (src->pw_name);
- dest->pw_passwd = xstrdup (src->pw_passwd);
- dest->pw_uid = src->pw_uid;
- dest->pw_gid = src->pw_gid;
- dest->pw_gecos = xstrdup (src->pw_gecos);
- dest->pw_dir = xstrdup (src->pw_dir);
- dest->pw_shell = xstrdup (src->pw_shell);
- return (failed);
-}
+/* Set up the limits so that we're not foiled */
-static char *xstrdup (char *str)
+static void
+pw_init()
{
- char *dup;
-
- if (! str)
- return NULL;
- dup = (char *) malloc (strlen (str) + 1);
- if (! dup) {
- failed = -1;
- return NULL;
- }
- strcpy (dup, str);
- return dup;
-}
+ struct rlimit rlim;
-#ifdef NO_PUTPWENT
-
-int putpwent (const struct passwd *p, FILE *stream)
-{
- if (p == NULL || stream == NULL) {
- errno = EINVAL;
- return (-1);
- }
- if (fprintf (stream, "%s:%s:%u:%u:%s:%s:%s\n",
- p->pw_name, p->pw_passwd, p->pw_uid, p->pw_gid,
- p->pw_gecos, p->pw_dir, p->pw_shell) < 0)
- return (-1);
- return(0);
-}
+ /* Unlimited resource limits. */
+ rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
+ setrlimit(RLIMIT_CPU, &rlim);
+ setrlimit(RLIMIT_FSIZE, &rlim);
+ setrlimit(RLIMIT_STACK, &rlim);
+ setrlimit(RLIMIT_DATA, &rlim);
+ setrlimit(RLIMIT_RSS, &rlim);
+#ifndef DEBUG
+ /* Don't drop core (not really necessary, but GP's). */
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlim);
#endif
-static void
-pw_init()
-{
- struct rlimit rlim;
-
- /* Unlimited resource limits. */
- rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
- (void)setrlimit(RLIMIT_CPU, &rlim);
- (void)setrlimit(RLIMIT_FSIZE, &rlim);
- (void)setrlimit(RLIMIT_STACK, &rlim);
- (void)setrlimit(RLIMIT_DATA, &rlim);
- (void)setrlimit(RLIMIT_RSS, &rlim);
-
- /* Don't drop core (not really necessary, but GP's). */
- rlim.rlim_cur = rlim.rlim_max = 0;
- (void)setrlimit(RLIMIT_CORE, &rlim);
-
- /* Turn off signals. */
- (void)signal(SIGALRM, SIG_IGN);
- (void)signal(SIGHUP, SIG_IGN);
- (void)signal(SIGINT, SIG_IGN);
- (void)signal(SIGPIPE, SIG_IGN);
- (void)signal(SIGQUIT, SIG_IGN);
- (void)signal(SIGTERM, SIG_IGN);
- (void)signal(SIGTSTP, SIG_IGN);
- (void)signal(SIGTTOU, SIG_IGN);
-
- /* Create with exact permissions. */
- (void)umask(0);
+ /* Turn off signals. */
+ signal(SIGALRM, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+
+ /* Create with exact permissions. */
+ umask(0);
}