[PATCH]passwd: size reduction and clean up

Bernhard Fischer rep.nop at aon.at
Thu Dec 29 12:48:35 UTC 2005


On Thu, Dec 29, 2005 at 01:49:52AM +0100, Tito wrote:
>Hi,
>I know that we are in feature freeze, but this patch is trivial...
>The patch changes:
>
>a) getopt -> bb_getopt_ulflags
>b) fprintf(stderr ... -> bb_error_msg/bb_perror_msg
>c) some minor hacks to save space.
>d) adds a GPL license text
>e) adds some CLEANUP stuff
>
>Size reduction is:
>  text    data     bss     dec     hex filename
>   3243       0     160    3403     d4b passwd.o.orig
>   3025       0     160    3185     c71 passwd.o
>
>I tested the patch a few times on my box and it worked fine.
>
>Please take a look at it and apply or save for 1.2.

What do you think about the attached further size reduction?

   text    data     bss     dec     hex filename
   3159       0     160    3319     cf7 loginutils/passwd.o.oorig
   2947       0     160    3107     c23 loginutils/passwd.o.tito
   2871       0     160    3031     bd7 loginutils/passwd.o

I only compile-tested this with gcc-4.1, so please check with your
compiler if these help you or not. Perhaps also look if another applet
uses something like i64c(), we could move it onto a common place then.

Note how it saves space to reuse the same strings and how reusing the
block near rename() helps the size, too.

Also replaced bzero (which is deprecated in favour of memset, nowadays)
while at it.

cheers,
Bernhard
-------------- next part --------------
   text    data     bss     dec     hex filename
   3159       0     160    3319     cf7 loginutils/passwd.o.oorig
   2947       0     160    3107     c23 loginutils/passwd.o.tito
   2871       0     160    3031     bd7 loginutils/passwd.o

Index: busybox/loginutils/passwd.c
===================================================================
--- busybox/loginutils/passwd.c	(revision 13010)
+++ busybox/loginutils/passwd.c	(working copy)
@@ -1,4 +1,13 @@
 /* vi: set sw=4 ts=4: */
+/*
+ * Mini passwd implementation for busybox
+ *
+ * Copyright (C) many different people.
+ * If you wrote this, please acknowledge your work.
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
 #include <fcntl.h>
 #include <stdio.h>
 #include <string.h>
@@ -18,19 +27,8 @@
 
 static int create_backup(const char *backup, FILE * fp);
 static int new_password(const struct passwd *pw, int amroot, int algo);
-static void set_filesize_limit(int blocks);
 
 
-static int get_algo(char *a)
-{
-	int x = 1;					/* standard: MD5 */
-
-	if (strcasecmp(a, "des") == 0)
-		x = 0;
-	return x;
-}
-
-
 static int update_passwd(const struct passwd *pw, char *crypt_pw)
 {
 	char filename[1024];
@@ -39,7 +37,6 @@
 	char username[32];
 	char *pw_rest;
 	int mask;
-	int continued;
 	FILE *fp;
 	FILE *out_fp;
 	struct stat sb;
@@ -65,7 +62,7 @@
 	lock.l_start = 0;
 	lock.l_len = 0;
 	if (fcntl(fileno(fp), F_SETLK, &lock) < 0) {
-		fprintf(stderr, "%s: %s\n", filename, strerror(errno));
+		bb_perror_msg("%s", filename);
 		return 1;
 	}
 	lock.l_type = F_UNLCK;
@@ -88,13 +85,15 @@
 		return 1;
 	}
 
-	continued = 0;
+	/* reuse mask to determine if the line is "continued" */
+	mask = 0;
 	snprintf(username, sizeof username, "%s:", pw->pw_name);
 	rewind(fp);
 	while (!feof(fp)) {
 		fgets(buffer, sizeof buffer, fp);
-		if (!continued) {		// Check to see if we're updating this line.
-			if (strncmp(username, buffer, strlen(username)) == 0) {	// we have a match.
+		if (!mask) {		/* Check to see if we're updating this line. */
+			if (strncmp(username, buffer, strlen(username)) == 0) {
+				/* we have a match. */
 				pw_rest = strchr(buffer, ':');
 				*pw_rest++ = '\0';
 				pw_rest = strchr(pw_rest, ':');
@@ -106,11 +105,11 @@
 			fputs(buffer, out_fp);
 		}
 		if (buffer[strlen(buffer) - 1] == '\n') {
-			continued = 0;
+			mask = 0;
 		} else {
-			continued = 1;
+			mask = 1;
 		}
-		bzero(buffer, sizeof buffer);
+		memset(buffer, 0, sizeof buffer);
 	}
 
 	if (fflush(out_fp) || fsync(fileno(out_fp)) || fclose(out_fp)) {
@@ -119,17 +118,18 @@
 		fclose(fp);
 		return 1;
 	}
+	fcntl(fileno(fp), F_SETLK, &lock);
+	fclose(fp);
 	if (rename(buf, filename) < 0) {
-		fcntl(fileno(fp), F_SETLK, &lock);
-		fclose(fp);
 		return 1;
-	} else {
-		fcntl(fileno(fp), F_SETLK, &lock);
-		fclose(fp);
-		return 0;
 	}
+	return 0;
 }
 
+#define OPT_ALGO	1
+#define OPT_LOCK	2
+#define OPT_UNLOCK	4
+#define OPT_DELETE	8
 
 extern int passwd_main(int argc, char **argv)
 {
@@ -138,53 +138,38 @@
 	char *np;
 	char *name;
 	char *myname;
-	int flag;
-	int algo = 1;				/* -a - password algorithm */
-	int lflg = 0;				/* -l - lock account */
-	int uflg = 0;				/* -u - unlock account */
-	int dflg = 0;				/* -d - delete password */
+	int algo = 1;
 	const struct passwd *pw;
+	unsigned long opt;
+	char *algo_arg;
 
 #ifdef CONFIG_FEATURE_SHADOWPASSWDS
 	const struct spwd *sp;
 #endif							/* CONFIG_FEATURE_SHADOWPASSWDS */
 	amroot = (getuid() == 0);
-	openlog("passwd", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH);
-	while ((flag = getopt(argc, argv, "a:dlu")) != EOF) {
-		switch (flag) {
-		case 'a':
-			algo = get_algo(optarg);
-			break;
-		case 'd':
-			dflg++;
-			break;
-		case 'l':
-			lflg++;
-			break;
-		case 'u':
-			uflg++;
-			break;
-		default:
-			bb_show_usage();
-		}
-	}
+	openlog(bb_applet_name, LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH);
+	/* -a - password algorithm */
+	/* -d - delete password */
+	/* -l - lock account */
+	/* -u - unlock account */
+	opt = bb_getopt_ulflags (argc, argv, "a:dlu", &algo_arg);
+
+	if (opt & OPT_ALGO)
+		algo = (strcasecmp(algo_arg, "des") == 0) ? 0 : 1;
+
 	myname = (char *) bb_xstrdup(bb_getpwuid(NULL, getuid(), -1));
 	/* exits on error */
-	if (optind < argc) {
-		name = argv[optind];
-	} else {
-		name = myname;
-	}
-	if ((lflg || uflg || dflg) && (optind >= argc || !amroot)) {
+	name = (optind < argc) ? argv[optind] : myname;
+	if ((opt > 1) && (optind >= argc || !amroot)) {
+		/* OPT_LOCK || OPT_UNLOCK || OPT_DELETE are set */
 		bb_show_usage();
 	}
-	pw = getpwnam(name);
-	if (!pw) {
-		bb_error_msg_and_die("Unknown user %s\n", name);
-	}
+	/* exits on error and saves an error message "Unknown user XXXX" */
+	pw = getpwuid(bb_xgetpwnam(name));
 	if (!amroot && pw->pw_uid != getuid()) {
-		syslog(LOG_WARNING, "can't change pwd for `%s'", name);
-		bb_error_msg_and_die("Permission denied.\n");
+		syslog(LOG_WARNING, "The password for `%s' cannot be changed.", name);
+		errno = EACCES;
+		bb_perror_nomsg_and_die(); /* Permission denied */
 	}
 #ifdef CONFIG_FEATURE_SHADOWPASSWDS
 	sp = getspnam(name);
@@ -199,40 +184,49 @@
 #endif							/* CONFIG_FEATURE_SHADOWPASSWDS */
 
 	safe_strncpy(crypt_passwd, cp, sizeof(crypt_passwd));
-	if (!(dflg || lflg || uflg)) {
+	if (opt<= 1) {
+		/* OPT_LOCK || OPT_UNLOCK || OPT_DELETE are not set */
 		if (!amroot) {
 			if (cp[0] == '!') {
-				syslog(LOG_WARNING, "password locked for `%s'", np);
-				bb_error_msg_and_die( "The password for `%s' cannot be changed.\n", np);
+				syslog(LOG_WARNING, "The password for `%s' cannot be changed.",
+						np);
+				bb_error_msg_and_die("The password for `%s' cannot be changed.",
+						np);
 			}
 		}
 		printf("Changing password for %s\n", name);
 		if (new_password(pw, amroot, algo)) {
-			bb_error_msg_and_die( "The password for %s is unchanged.\n", name);
+			bb_error_msg_and_die( "The password for %s is unchanged.", name);
 		}
-	} else if (lflg) {
+	} else if (opt & OPT_LOCK) {
 		if (crypt_passwd[0] != '!') {
 			memmove(&crypt_passwd[1], crypt_passwd,
 					sizeof crypt_passwd - 1);
 			crypt_passwd[sizeof crypt_passwd - 1] = '\0';
 			crypt_passwd[0] = '!';
 		}
-	} else if (uflg) {
+	} else if (opt & OPT_UNLOCK) {
 		if (crypt_passwd[0] == '!') {
 			memmove(crypt_passwd, &crypt_passwd[1],
 					sizeof crypt_passwd - 1);
 		}
-	} else if (dflg) {
+	} else if (opt & OPT_DELETE) {
 		crypt_passwd[0] = '\0';
 	}
-	set_filesize_limit(30000);
+	{
+		struct rlimit rlimit_fsize;
+
+		rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * 30000;
+		setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
+	}
 	signal(SIGHUP, SIG_IGN);
 	signal(SIGINT, SIG_IGN);
 	signal(SIGQUIT, SIG_IGN);
 	umask(077);
+	/* Maybe not needed as passwd sets _BB_SUID_ALWAYS ? */
 	if (setuid(0)) {
-		syslog(LOG_ERR, "can't setuid(0)");
-		bb_error_msg_and_die( "Cannot change ID to root.\n");
+		syslog(LOG_ERR, "Cannot change ID to root.");
+		bb_error_msg_and_die( "Cannot change ID to root.");
 	}
 	if (!update_passwd(pw, crypt_passwd)) {
 		syslog(LOG_INFO, "password for `%s' changed by user `%s'", name,
@@ -240,8 +234,9 @@
 		printf("Password changed.\n");
 	} else {
 		syslog(LOG_WARNING, "an error occurred updating the password file");
-		bb_error_msg_and_die("An error occurred updating the password file.\n");
+		bb_error_msg_and_die("an error occurred updating the password file");
 	}
+	if (ENABLE_FEATURE_CLEAN_UP) free(myname);
 	return (0);
 }
 
@@ -332,7 +327,7 @@
 		}
 		cipher = pw_encrypt(clear, crypt_passwd);
 		if (strcmp(cipher, crypt_passwd) != 0) {
-			syslog(LOG_WARNING, "incorrect password for `%s'",
+			syslog(LOG_WARNING, "Incorrect password for `%s'",
 				   pw->pw_name);
 			time(&start);
 			now = start;
@@ -340,13 +335,13 @@
 				sleep(FAIL_DELAY);
 				time(&now);
 			}
-			fprintf(stderr, "Incorrect password.\n");
+			bb_error_msg("Incorrect password.");
 			/* return -1; */
 			return 1;
 		}
 		safe_strncpy(orig, clear, sizeof(orig));
-		bzero(clear, strlen(clear));
-		bzero(cipher, strlen(cipher));
+		memset(clear, 0, strlen(clear));
+		memset(cipher, 0, strlen(cipher));
 	} else {
 		orig[0] = '\0';
 	}
@@ -354,12 +349,12 @@
 					  "Please use a combination of upper and lower case letters and numbers.\n"
 					  "Enter new password: ")))
 	{
-		bzero(orig, sizeof orig);
+		memset(orig, 0, sizeof orig);
 		/* return -1; */
 		return 1;
 	}
 	safe_strncpy(pass, cp, sizeof(pass));
-	bzero(cp, strlen(cp));
+	memset(cp, 0, strlen(cp));
 	/* if (!obscure(orig, pass, pw)) { */
 	if (obscure(orig, pass, pw)) {
 		if (amroot) {
@@ -370,31 +365,24 @@
 		}
 	}
 	if (!(cp = bb_askpass(0, "Re-enter new password: "))) {
-		bzero(orig, sizeof orig);
+		memset(orig, 0, sizeof orig);
 		/* return -1; */
 		return 1;
 	}
 	if (strcmp(cp, pass)) {
-		fprintf(stderr, "Passwords do not match.\n");
+		bb_error_msg("Passwords do not match.");
 		/* return -1; */
 		return 1;
 	}
-	bzero(cp, strlen(cp));
-	bzero(orig, sizeof(orig));
+	memset(cp, 0, strlen(cp));
+	memset(orig, 0, sizeof(orig));
 
 	if (algo == 1) {
 		cp = pw_encrypt(pass, "$1$");
 	} else
 		cp = pw_encrypt(pass, crypt_make_salt());
-	bzero(pass, sizeof pass);
+	memset(pass, 0, sizeof pass);
 	safe_strncpy(crypt_passwd, cp, sizeof(crypt_passwd));
 	return 0;
 }
 
-static void set_filesize_limit(int blocks)
-{
-	struct rlimit rlimit_fsize;
-
-	rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * blocks;
-	setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
-}


More information about the busybox mailing list