Subject: pw_copy() and error handling
To: NetBSD Userlevel Technical Discussion List <tech-userlevel@netbsd.org>
From: Jason Thorpe <thorpej@wasabisystems.com>
List: tech-userlevel
Date: 08/02/2004 11:47:57
--Apple-Mail-14--651355829
Content-Type: multipart/mixed; boundary=Apple-Mail-13--651355849
--Apple-Mail-13--651355849
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
charset=US-ASCII;
format=flowed
Hi folks...
I'm working on an application that uses the password file routines in
libutil, and have found pw_copy()'s error handling to be less than
ideal. Specifically, it writes an error message to stderr and then
exits the process. What I need to do is return an error condition to
my application, which will then perform its own cleanup procedures.
What I did was morph pw_copy() into a new pw_copyx() that returns a
success / failure indication, and fills in a buffer with the error
message. I then added a pw_copy() wrapper around the new pw_copyx()
that mimics the old behavior.
Patch attached. Does anyone object to me committing it?
-- Jason R. Thorpe <thorpej@wasabisystems.com>
--Apple-Mail-13--651355849
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
x-unix-mode=0644;
name="pw_copyx-patch.txt"
Content-Disposition: attachment;
filename=pw_copyx-patch.txt
Index: include/util.h
===================================================================
RCS file: /cvsroot/src/include/util.h,v
retrieving revision 1.31
diff -u -p -r1.31 util.h
--- include/util.h 7 Aug 2003 09:44:11 -0000 1.31
+++ include/util.h 2 Aug 2004 18:41:03 -0000
@@ -82,6 +82,8 @@ int pidfile(const char *);
int pidlock(const char *, int, pid_t *, const char *);
int pw_abort(void);
void pw_copy(int, int, struct passwd *, struct passwd *);
+int pw_copyx(int, int, struct passwd *, struct passwd *,
+ char *, size_t);
void pw_edit(int, const char *);
void pw_error(const char *, int, int);
void pw_getconf(char *, size_t, const char *, const char *);
Index: lib/libutil/passwd.c
===================================================================
RCS file: /cvsroot/src/lib/libutil/passwd.c,v
retrieving revision 1.35
diff -u -p -r1.35 passwd.c
--- lib/libutil/passwd.c 7 Aug 2003 16:44:59 -0000 1.35
+++ lib/libutil/passwd.c 2 Aug 2004 18:41:04 -0000
@@ -320,77 +320,118 @@ pw_equal(char *buf, struct passwd *pw)
void
pw_copy(int ffd, int tfd, struct passwd *pw, struct passwd *old_pw)
{
+ char errbuf[200];
+ int rv;
+
+ rv = pw_copyx(ffd, tfd, pw, old_pw, errbuf, sizeof(errbuf));
+ if (rv == 0) {
+ warnx("%s", errbuf);
+ pw_error(NULL, 0, 1);
+ }
+}
+
+int
+pw_copyx(int ffd, int tfd, struct passwd *pw, struct passwd *old_pw,
+ char *errbuf, size_t errbufsz)
+{
const char *filename;
char mpwd[MAXPATHLEN], mpwdl[MAXPATHLEN], *p, buf[8192];
FILE *from, *to;
int done;
_DIAGASSERT(pw != NULL);
+ _DIAGASSERT(errbuf != NULL);
/* old_pw may be NULL */
- if ((filename = pw_filename(_PATH_MASTERPASSWD)) == NULL)
- pw_error(pw_prefix, 1,1);
+ if ((filename = pw_filename(_PATH_MASTERPASSWD)) == NULL) {
+ snprintf(errbuf, errbufsz, "%s: %s", pw_prefix,
+ strerror(errno));
+ return (0);
+ }
(void)strcpy(mpwd, filename);
- if ((filename = pw_filename(_PATH_MASTERPASSWD_LOCK)) == NULL)
- pw_error(pw_prefix, 1,1);
+ if ((filename = pw_filename(_PATH_MASTERPASSWD_LOCK)) == NULL) {
+ snprintf(errbuf, errbufsz, "%s: %s", pw_prefix,
+ strerror(errno));
+ return (0);
+ }
(void)strcpy(mpwdl, filename);
- if (!(from = fdopen(ffd, "r")))
- pw_error(mpwd, 1, 1);
- if (!(to = fdopen(tfd, "w")))
- pw_error(mpwdl, 1, 1);
+ if (!(from = fdopen(ffd, "r"))) {
+ snprintf(errbuf, errbufsz, "%s: %s", mpwd, strerror(errno));
+ return (0);
+ }
+ if (!(to = fdopen(tfd, "w"))) {
+ snprintf(errbuf, errbufsz, "%s: %s", mpwdl, strerror(errno));
+ return (0);
+ }
for (done = 0; fgets(buf, sizeof(buf), from);) {
if (!strchr(buf, '\n')) {
- warnx("%s: line too long", mpwd);
- pw_error(NULL, 0, 1);
+ snprintf(errbuf, errbufsz, "%s: line too long", mpwd);
+ return (0);
}
if (done) {
(void)fprintf(to, "%s", buf);
- if (ferror(to))
- goto err;
+ if (ferror(to)) {
+ snprintf(errbuf, errbufsz, "%s",
+ strerror(errno));
+ return (0);
+ }
continue;
}
if (!(p = strchr(buf, ':'))) {
- warnx("%s: corrupted entry", mpwd);
- pw_error(NULL, 0, 1);
+ snprintf(errbuf, errbufsz, "%s: corrupted entry", mpwd);
+ return (0);
}
*p = '\0';
if (strcmp(buf, pw->pw_name)) {
*p = ':';
(void)fprintf(to, "%s", buf);
- if (ferror(to))
- goto err;
+ if (ferror(to)) {
+ snprintf(errbuf, errbufsz, "%s",
+ strerror(errno));
+ return (0);
+ }
continue;
}
*p = ':';
if (old_pw && !pw_equal(buf, old_pw)) {
- warnx("%s: entry inconsistent", mpwd);
- pw_error(NULL, 0, 1);
+ snprintf(errbuf, errbufsz, "%s: entry inconsistent",
+ mpwd);
+ return (0);
}
(void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid,
pw->pw_class, (long)pw->pw_change, (long)pw->pw_expire,
pw->pw_gecos, pw->pw_dir, pw->pw_shell);
done = 1;
- if (ferror(to))
- goto err;
+ if (ferror(to)) {
+ snprintf(errbuf, errbufsz, "%s", strerror(errno));
+ return (0);
+ }
}
/* Only append a new entry if real uid is root! */
if (!done) {
- if (getuid() == 0)
+ if (getuid() == 0) {
(void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid,
pw->pw_class, (long)pw->pw_change,
(long)pw->pw_expire, pw->pw_gecos, pw->pw_dir,
pw->pw_shell);
- else
- warnx("%s: changes not made, no such entry", mpwd);
+ done = 1;
+ } else {
+ snprintf(errbuf, errbufsz,
+ "%s: changes not made, no such entry", mpwd);
+ }
}
- if (ferror(to))
-err: pw_error(NULL, 1, 1);
+ if (ferror(to)) {
+ snprintf(errbuf, errbufsz, "%s", strerror(errno));
+ return (0);
+ }
(void)fclose(to);
+
+ return (done);
}
void
Index: lib/libutil/pw_init.3
===================================================================
RCS file: /cvsroot/src/lib/libutil/pw_init.3,v
retrieving revision 1.12
diff -u -p -r1.12 pw_init.3
--- lib/libutil/pw_init.3 7 Aug 2003 16:45:00 -0000 1.12
+++ lib/libutil/pw_init.3 2 Aug 2004 18:41:04 -0000
@@ -31,7 +31,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 15, 1995
+.Dd August 1, 2004
.Dt PW_INIT 3
.Os
.Sh NAME
@@ -39,6 +39,7 @@
.Nm pw_edit ,
.Nm pw_prompt ,
.Nm pw_copy ,
+.Nm pw_copyx ,
.Nm pw_scan ,
.Nm pw_error
.Nd utility functions for interactive passwd file updates
@@ -56,6 +57,9 @@
.Ft void
.Fn pw_copy "int ffd" "int tfd" "struct passwd *pw" "struct passwd *old_pw"
.Ft int
+.Fn pw_copyx "int ffd" "int tfd" "struct passwd *pw" "struct passwd *old_pw" \
+ "char *errbuf" "size_t errbufsz"
+.Ft int
.Fn pw_scan "char *bp" "struct passwd *pw" "int *flags"
.Ft void
.Fn pw_error "const char *name" "int err" "int eval"
@@ -115,7 +119,24 @@ or the process is aborted.
If an entry is not found to match
.Fa pw ,
a new entry is appended to the passwd file only if the real user
-ID is 0.
+ID is 0. If an error occurs,
+.Fn pw_copy
+will display a message on
+.Dv stderr
+and call
+.Fn pw_error .
+.Pp
+The
+.Fn pw_copyx
+function performs the same operation as
+.Fn pw_copy
+with the exception of error handling.
+Upon an error,
+.Fn pw_copyx
+will write an error message into the buffer pointed to by
+.Fa errbuf
+which has the size
+.Fa errbufsz .
.Pp
The
.Fn pw_scan
@@ -182,6 +203,11 @@ The process exits with status
.Fa eval .
.Sh RETURN VALUES
The
+.Fn pw_copyx
+function returns 1 if the new password entry was successfully written
+to the destination file, and 0 otherwise.
+.Pp
+The
.Fn pw_scan
function prints a warning message and returns 0 if the string in the
.Fa bp
--Apple-Mail-13--651355849--
--Apple-Mail-14--651355829
content-type: application/pgp-signature; x-mac-type=70674453;
name=PGP.sig
content-description: This is a digitally signed message part
content-disposition: inline; filename=PGP.sig
content-transfer-encoding: 7bit
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (Darwin)
iD4DBQFBDoxdOpVKkaBm8XkRArf9AJ43hzM19tNGVgLjZISmLwH/KeaW9ACWMSU/
EFUTXQ4aft3LBxYiQD4hPw==
=Kt9w
-----END PGP SIGNATURE-----
--Apple-Mail-14--651355829--