aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-07-20 21:29:49 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-07-20 21:29:49 +0000
commit1ec5eaecba0a0323f214825b83fabcc18a41884d (patch)
treed2dee2f7f0d1e5f3dd62be4f6cc4a6d5e274ac5c
parent21d1014b5b91d1a1319273945291b7a9f4717827 (diff)
downloadbusybox-w32-1ec5eaecba0a0323f214825b83fabcc18a41884d.tar.gz
busybox-w32-1ec5eaecba0a0323f214825b83fabcc18a41884d.tar.bz2
busybox-w32-1ec5eaecba0a0323f214825b83fabcc18a41884d.zip
chpasswd: now with svn add
-rw-r--r--libbb/update_passwd.c119
-rw-r--r--loginutils/chpasswd.c77
2 files changed, 196 insertions, 0 deletions
diff --git a/libbb/update_passwd.c b/libbb/update_passwd.c
new file mode 100644
index 000000000..5572db547
--- /dev/null
+++ b/libbb/update_passwd.c
@@ -0,0 +1,119 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * update_passwd
4 *
5 * update_passwd is a common function for passwd and chpasswd applets;
6 * it is responsible for updating password file (i.e. /etc/passwd or
7 * /etc/shadow) for a given user and password.
8 *
9 * Moved from loginutils/passwd.c by Alexander Shishkin <virtuoso@slind.org>
10 */
11
12#include "libbb.h"
13
14int update_passwd(const char *filename, const char *username,
15 const char *new_pw)
16{
17 struct stat sb;
18 struct flock lock;
19 FILE *old_fp;
20 FILE *new_fp;
21 char *new_name;
22 char *last_char;
23 unsigned user_len;
24 int old_fd;
25 int new_fd;
26 int i;
27 int cnt = 0;
28 int ret = 1; /* failure */
29
30 /* New passwd file, "/etc/passwd+" for now */
31 new_name = xasprintf("%s+", filename);
32 last_char = &new_name[strlen(new_name)-1];
33 username = xasprintf("%s:", username);
34 user_len = strlen(username);
35
36 old_fp = fopen(filename, "r+");
37 if (!old_fp)
38 goto free_mem;
39 old_fd = fileno(old_fp);
40
41 /* Try to create "/etc/passwd+". Wait if it exists. */
42 i = 30;
43 do {
44 // FIXME: on last iteration try w/o O_EXCL but with O_TRUNC?
45 new_fd = open(new_name, O_WRONLY|O_CREAT|O_EXCL,0600);
46 if (new_fd >= 0) goto created;
47 if (errno != EEXIST) break;
48 usleep(100000); /* 0.1 sec */
49 } while (--i);
50 bb_perror_msg("cannot create '%s'", new_name);
51 goto close_old_fp;
52
53 created:
54 if (!fstat(old_fd, &sb)) {
55 fchmod(new_fd, sb.st_mode & 0777); /* ignore errors */
56 fchown(new_fd, sb.st_uid, sb.st_gid);
57 }
58 new_fp = fdopen(new_fd, "w");
59 if (!new_fp) {
60 close(new_fd);
61 goto unlink_new;
62 }
63
64 /* Backup file is "/etc/passwd-" */
65 last_char[0] = '-';
66 /* Delete old one, create new as a hardlink to current */
67 i = (unlink(new_name) && errno != ENOENT);
68 if (i || link(filename, new_name))
69 bb_perror_msg("warning: cannot create backup copy '%s'", new_name);
70 last_char[0] = '+';
71
72 /* Lock the password file before updating */
73 lock.l_type = F_WRLCK;
74 lock.l_whence = SEEK_SET;
75 lock.l_start = 0;
76 lock.l_len = 0;
77 if (fcntl(old_fd, F_SETLK, &lock) < 0)
78 bb_perror_msg("warning: cannot lock '%s'", filename);
79 lock.l_type = F_UNLCK;
80
81 /* Read current password file, write updated one */
82 while (1) {
83 char *line = xmalloc_fgets(old_fp);
84 if (!line) break; /* EOF/error */
85 if (strncmp(username, line, user_len) == 0) {
86 /* we have a match with "username:"... */
87 const char *cp = line + user_len;
88 /* now cp -> old passwd, skip it: */
89 cp = strchr(cp, ':');
90 if (!cp) cp = "";
91 /* now cp -> ':' after old passwd or -> "" */
92 fprintf(new_fp, "%s%s%s", username, new_pw, cp);
93 cnt++;
94 } else
95 fputs(line, new_fp);
96 free(line);
97 }
98 fcntl(old_fd, F_SETLK, &lock);
99
100 /* We do want all of them to execute, thus | instead of || */
101 if ((ferror(old_fp) | fflush(new_fp) | fsync(new_fd) | fclose(new_fp))
102 || rename(new_name, filename)
103 ) {
104 /* At least one of those failed */
105 goto unlink_new;
106 }
107 ret = cnt; /* whee, success! */
108
109 unlink_new:
110 if (ret) unlink(new_name);
111
112 close_old_fp:
113 fclose(old_fp);
114
115 free_mem:
116 if (ENABLE_FEATURE_CLEAN_UP) free(new_name);
117 if (ENABLE_FEATURE_CLEAN_UP) free((char*)username);
118 return ret;
119}
diff --git a/loginutils/chpasswd.c b/loginutils/chpasswd.c
new file mode 100644
index 000000000..124fc86e2
--- /dev/null
+++ b/loginutils/chpasswd.c
@@ -0,0 +1,77 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * chpasswd.c
4 *
5 * Written for SLIND (from passwd.c) by Alexander Shishkin <virtuoso@slind.org>
6 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
7 */
8
9#include "libbb.h"
10
11#if ENABLE_GETOPT_LONG
12#include <getopt.h>
13
14static const struct option chpasswd_opts[] = {
15 { "encrypted", no_argument, NULL, 'e' },
16 { "md5", no_argument, NULL, 'm' },
17 { NULL, 0, NULL, 0 }
18};
19#endif
20
21#define OPT_ENC 1
22#define OPT_MD5 2
23
24int chpasswd_main(int argc, char **argv);
25int chpasswd_main(int argc, char **argv)
26{
27 char *name, *pass;
28 char salt[sizeof("$N$XXXXXXXX")];
29 int opt, rc;
30 int rnd = rnd; /* we *want* it to be non-initialized! */
31 const char *pwfile = bb_path_passwd_file;
32
33 if (getuid() != 0)
34 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
35
36#if ENABLE_FEATURE_SHADOWPASSWDS
37 if (access(bb_path_shadow_file, F_OK) == 0)
38 pwfile = bb_path_shadow_file;
39#endif
40
41 opt_complementary = "m--e";
42 USE_GETOPT_LONG(applet_long_options = chpasswd_opts;)
43 opt = getopt32(argc, argv, "em");
44
45 while ((name = xmalloc_getline(stdin)) != NULL) {
46 pass = strchr(name, ':');
47 if (!pass)
48 bb_error_msg_and_die("missing new password");
49 *pass++ = '\0';
50
51 //if (!getpwnam(name))
52 // bb_error_msg_and_die("unknown user %s", name);
53
54 if (!(opt & OPT_ENC)) {
55 rnd = crypt_make_salt(salt, 1, rnd);
56 if (opt & OPT_MD5) {
57 strcpy(salt, "$1$");
58 rnd = crypt_make_salt(salt + 3, 4, rnd);
59 }
60 pass = pw_encrypt(pass, salt);
61 }
62
63 rc = update_passwd(pwfile, name, pass);
64 /* LOGMODE_BOTH logs to syslog */
65 logmode = LOGMODE_BOTH;
66 if (rc < 0)
67 bb_error_msg_and_die("an error occurred updating %s", pwfile);
68 if (rc > 0)
69 bb_info_msg("Password for '%s' changed", name);
70 else
71 bb_info_msg("User '%s' not found", name);
72 logmode = LOGMODE_STDIO;
73 free(name);
74 }
75
76 return 0;
77}