blob: fb7a24126bc453d3f94cd2e894c74982b1d1b750
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 source tree. |
7 | */ |
8 | //config:config CHPASSWD |
9 | //config: bool "chpasswd" |
10 | //config: default y |
11 | //config: help |
12 | //config: Reads a file of user name and password pairs from standard input |
13 | //config: and uses this information to update a group of existing users. |
14 | //config: |
15 | //config:config FEATURE_DEFAULT_PASSWD_ALGO |
16 | //config: string "Default password encryption method (passwd -a, cryptpw -m parameter)" |
17 | //config: default "des" |
18 | //config: depends on PASSWD || CRYPTPW |
19 | //config: help |
20 | //config: Possible choices are "d[es]", "m[d5]", "s[ha256]" or "sha512". |
21 | |
22 | //applet:IF_CHPASSWD(APPLET(chpasswd, BB_DIR_USR_SBIN, BB_SUID_DROP)) |
23 | |
24 | //kbuild:lib-$(CONFIG_CHPASSWD) += chpasswd.o |
25 | |
26 | //usage:#define chpasswd_trivial_usage |
27 | //usage: IF_LONG_OPTS("[--md5|--encrypted|--crypt-method]") IF_NOT_LONG_OPTS("[-m|-e|-c]") |
28 | //usage:#define chpasswd_full_usage "\n\n" |
29 | //usage: "Read user:password from stdin and update /etc/passwd\n" |
30 | //usage: IF_LONG_OPTS( |
31 | //usage: "\n -e,--encrypted Supplied passwords are in encrypted form" |
32 | //usage: "\n -m,--md5 Use MD5 encryption instead of DES" |
33 | //usage: "\n -c,--crypt-method Use the specified method to encrypt the passwords" |
34 | //usage: ) |
35 | //usage: IF_NOT_LONG_OPTS( |
36 | //usage: "\n -e Supplied passwords are in encrypted form" |
37 | //usage: "\n -m Use MD5 encryption instead of DES" |
38 | //usage: "\n -c Use the specified method to encrypt the passwords" |
39 | //usage: ) |
40 | |
41 | #include "libbb.h" |
42 | |
43 | #if ENABLE_LONG_OPTS |
44 | static const char chpasswd_longopts[] ALIGN1 = |
45 | "encrypted\0" No_argument "e" |
46 | "md5\0" No_argument "m" |
47 | "crypt-method\0" Required_argument "c" |
48 | ; |
49 | #endif |
50 | |
51 | #define OPT_ENC 1 |
52 | #define OPT_MD5 2 |
53 | |
54 | int chpasswd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
55 | int chpasswd_main(int argc UNUSED_PARAM, char **argv) |
56 | { |
57 | char *name; |
58 | const char *algo = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO; |
59 | int opt; |
60 | |
61 | if (getuid() != 0) |
62 | bb_error_msg_and_die("%s", bb_msg_perm_denied_are_you_root); |
63 | |
64 | opt_complementary = "m--ec:e--mc:c--em"; |
65 | IF_LONG_OPTS(applet_long_options = chpasswd_longopts;) |
66 | opt = getopt32(argv, "emc:", &algo); |
67 | |
68 | while ((name = xmalloc_fgetline(stdin)) != NULL) { |
69 | char *free_me; |
70 | char *pass; |
71 | int rc; |
72 | |
73 | pass = strchr(name, ':'); |
74 | if (!pass) |
75 | bb_error_msg_and_die("missing new password"); |
76 | *pass++ = '\0'; |
77 | |
78 | xuname2uid(name); /* dies if there is no such user */ |
79 | |
80 | free_me = NULL; |
81 | if (!(opt & OPT_ENC)) { |
82 | char salt[MAX_PW_SALT_LEN]; |
83 | |
84 | if (opt & OPT_MD5) { |
85 | /* Force MD5 if the -m flag is set */ |
86 | algo = "md5"; |
87 | } |
88 | |
89 | crypt_make_pw_salt(salt, algo); |
90 | free_me = pass = pw_encrypt(pass, salt, 0); |
91 | } |
92 | |
93 | /* This is rather complex: if user is not found in /etc/shadow, |
94 | * we try to find & change his passwd in /etc/passwd */ |
95 | #if ENABLE_FEATURE_SHADOWPASSWDS |
96 | rc = update_passwd(bb_path_shadow_file, name, pass, NULL); |
97 | if (rc > 0) /* password in /etc/shadow was updated */ |
98 | pass = (char*)"x"; |
99 | if (rc >= 0) |
100 | /* 0 = /etc/shadow missing (not an error), >0 = passwd changed in /etc/shadow */ |
101 | #endif |
102 | rc = update_passwd(bb_path_passwd_file, name, pass, NULL); |
103 | /* LOGMODE_BOTH logs to syslog also */ |
104 | logmode = LOGMODE_BOTH; |
105 | if (rc < 0) |
106 | bb_error_msg_and_die("an error occurred updating password for %s", name); |
107 | if (rc) |
108 | bb_error_msg("password for '%s' changed", name); |
109 | logmode = LOGMODE_STDIO; |
110 | free(name); |
111 | free(free_me); |
112 | } |
113 | return EXIT_SUCCESS; |
114 | } |
115 |