summaryrefslogtreecommitdiffstats
path: root/login-utils/setpwnam.c
diff options
context:
space:
mode:
authorKarel Zak2006-12-07 00:25:32 +0100
committerKarel Zak2006-12-07 00:25:32 +0100
commit6dbe3af945a63f025561abb83275cee9ff06c57b (patch)
tree19e59eac8ac465b5bc409b5adf815b582c92f633 /login-utils/setpwnam.c
downloadkernel-qcow2-util-linux-6dbe3af945a63f025561abb83275cee9ff06c57b.tar.gz
kernel-qcow2-util-linux-6dbe3af945a63f025561abb83275cee9ff06c57b.tar.xz
kernel-qcow2-util-linux-6dbe3af945a63f025561abb83275cee9ff06c57b.zip
Imported from util-linux-2.2 tarball.
Diffstat (limited to 'login-utils/setpwnam.c')
-rw-r--r--login-utils/setpwnam.c209
1 files changed, 209 insertions, 0 deletions
diff --git a/login-utils/setpwnam.c b/login-utils/setpwnam.c
new file mode 100644
index 000000000..f7e6eb312
--- /dev/null
+++ b/login-utils/setpwnam.c
@@ -0,0 +1,209 @@
+/*
+ * setpwnam.c --
+ * edit an entry in a password database.
+ *
+ * (c) 1994 Salvatore Valente <svalente@mit.edu>
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed with no warranty.
+ *
+ * Usage:
+ * 1) get a struct passwd * from getpwnam().
+ * You should assume a struct passwd has an infinite number of fields,
+ * so you should not try to create one from scratch.
+ * 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().
+ *
+ * Thanks to "two guys named Ian".
+ */
+/* faith
+ * 1.1.1.1
+ * 1995/02/22 19:09:24
+ */
+
+#define DEBUG 0
+
+/* because I use getpwent(), putpwent(), etc... */
+#define _SVID_SOURCE
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <errno.h>
+#ifdef BSD43
+#include <sys/file.h>
+#endif
+
+extern int errno;
+
+typedef int boolean;
+#define false 0
+#define true 1
+
+#ifndef DEBUG
+#define PASSWD_FILE "/etc/passwd"
+#define PTMP_FILE "/etc/ptmp"
+#else
+#define PASSWD_FILE "/tmp/passwd"
+#define PTMP_FILE "/tmp/ptmp"
+#endif
+
+static int copy_pwd (struct passwd *src, struct passwd *dest);
+static char *xstrdup (char *str);
+
+/*
+ * 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
+ * replaced with the given entry.
+ */
+int setpwnam (struct passwd *pwd)
+{
+ char *passwd = PASSWD_FILE;
+ char *ptmp = PTMP_FILE;
+ FILE *fp;
+ int x, save_errno, fd;
+ struct passwd *entry;
+ boolean found;
+ char buf[50];
+ struct passwd spwd;
+
+ /* 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);
+
+ /* sanity check */
+ for (x = 0; x < 3; x++) {
+ if (x > 0) sleep (1);
+ fd = open (ptmp, O_WRONLY|O_CREAT|O_EXCL, 00644);
+ if (fd >= 0) break;
+ }
+ if (fd < 0) return (-1);
+
+ /* ptmp should be owned by root.root or root.wheel */
+ if (chown (ptmp, (uid_t) 0, (gid_t) 0) < 0)
+ perror ("chown");
+
+ /* open ptmp for writing and passwd for reading */
+ fp = fdopen (fd, "w");
+ if (! fp) goto fail;
+
+ setpwent ();
+
+ /* 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;
+ }
+ if (fclose (fp) < 0) goto fail;
+ close (fd);
+ endpwent ();
+
+ if (! found) {
+ errno = ENOENT; /* give me something better */
+ goto fail;
+ }
+
+ strcpy (buf, passwd);
+ strcat (buf, "~");
+ /* we don't care if we can't remove the backup file */
+ remove (buf);
+ /* we don't care if we can't create the backup file */
+ link (passwd, buf);
+ /* we DO care if we can't erase the passwd file */
+ if (remove (passwd) < 0) {
+ /* if the file is still there, fail */
+ if (access (passwd, F_OK) == 0) goto fail;
+ }
+ /* if we can't link ptmp to passwd, all is lost */
+ if (link (ptmp, passwd) < 0) {
+ /* reinstall_system (); */
+ return (-1);
+ }
+ /* if we can't erase the ptmp file, we simply lose */
+ if (remove (ptmp) < 0)
+ return (-1);
+ /* finally: success */
+ return 0;
+
+ fail:
+ save_errno = errno;
+ if (fp) fclose (fp);
+ if (fd >= 0) close (fd);
+ endpwent ();
+ remove (ptmp);
+ errno = save_errno;
+ 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);
+}
+
+static char *xstrdup (char *str)
+{
+ char *dup;
+
+ if (! str)
+ return NULL;
+ dup = (char *) malloc (strlen (str) + 1);
+ if (! dup) {
+ failed = -1;
+ return NULL;
+ }
+ strcpy (dup, str);
+ return dup;
+}
+
+#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);
+}
+
+#endif