source: branches/2.2.9/mindi-busybox/loginutils/passwd.c

Last change on this file was 3320, checked in by bruno, 5 years ago
  • Re-add (thanks git BTW) the 2.2.9 branch which had been destroyed in the move to 3.0
  • Property svn:eol-style set to native
File size: 5.6 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 */
5#include "libbb.h"
6#include <syslog.h>
7
8static void nuke_str(char *str)
9{
10    if (str) memset(str, 0, strlen(str));
11}
12
13static char* new_password(const struct passwd *pw, uid_t myuid, int algo)
14{
15    char salt[sizeof("$N$XXXXXXXX")]; /* "$N$XXXXXXXX" or "XX" */
16    char *orig = (char*)"";
17    char *newp = NULL;
18    char *cp = NULL;
19    char *ret = NULL; /* failure so far */
20
21    if (myuid && pw->pw_passwd[0]) {
22        char *encrypted;
23
24        orig = bb_ask_stdin("Old password: "); /* returns ptr to static */
25        if (!orig)
26            goto err_ret;
27        encrypted = pw_encrypt(orig, pw->pw_passwd, 1); /* returns malloced str */
28        if (strcmp(encrypted, pw->pw_passwd) != 0) {
29            syslog(LOG_WARNING, "incorrect password for %s",
30                pw->pw_name);
31            bb_do_delay(FAIL_DELAY);
32            puts("Incorrect password");
33            goto err_ret;
34        }
35        if (ENABLE_FEATURE_CLEAN_UP) free(encrypted);
36    }
37    orig = xstrdup(orig); /* or else bb_ask_stdin() will destroy it */
38    newp = bb_ask_stdin("New password: "); /* returns ptr to static */
39    if (!newp)
40        goto err_ret;
41    newp = xstrdup(newp); /* we are going to bb_ask_stdin() again, so save it */
42    if (ENABLE_FEATURE_PASSWD_WEAK_CHECK
43     && obscure(orig, newp, pw) && myuid)
44        goto err_ret; /* non-root is not allowed to have weak passwd */
45
46    cp = bb_ask_stdin("Retype password: ");
47    if (!cp)
48        goto err_ret;
49    if (strcmp(cp, newp)) {
50        puts("Passwords don't match");
51        goto err_ret;
52    }
53
54    crypt_make_salt(salt, 1, 0); /* des */
55    if (algo) { /* MD5 */
56        strcpy(salt, "$1$");
57        crypt_make_salt(salt + 3, 4, 0);
58    }
59    /* pw_encrypt returns malloced str */
60    ret = pw_encrypt(newp, salt, 1);
61    /* whee, success! */
62
63 err_ret:
64    nuke_str(orig);
65    if (ENABLE_FEATURE_CLEAN_UP) free(orig);
66    nuke_str(newp);
67    if (ENABLE_FEATURE_CLEAN_UP) free(newp);
68    nuke_str(cp);
69    return ret;
70}
71
72int passwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
73int passwd_main(int argc UNUSED_PARAM, char **argv)
74{
75    enum {
76        OPT_algo = 0x1, /* -a - password algorithm */
77        OPT_lock = 0x2, /* -l - lock account */
78        OPT_unlock = 0x4, /* -u - unlock account */
79        OPT_delete = 0x8, /* -d - delete password */
80        OPT_lud = 0xe,
81        STATE_ALGO_md5 = 0x10,
82        //STATE_ALGO_des = 0x20, not needed yet
83    };
84    unsigned opt;
85    int rc;
86    const char *opt_a = "";
87    const char *filename;
88    char *myname;
89    char *name;
90    char *newp;
91    struct passwd *pw;
92    uid_t myuid;
93    struct rlimit rlimit_fsize;
94    char c;
95#if ENABLE_FEATURE_SHADOWPASSWDS
96    /* Using _r function to avoid pulling in static buffers */
97    struct spwd spw;
98    char buffer[256];
99#endif
100
101    logmode = LOGMODE_BOTH;
102    openlog(applet_name, 0, LOG_AUTH);
103    opt = getopt32(argv, "a:lud", &opt_a);
104    //argc -= optind;
105    argv += optind;
106
107    if (strcasecmp(opt_a, "des") != 0) /* -a */
108        opt |= STATE_ALGO_md5;
109    //else
110    //  opt |= STATE_ALGO_des;
111    myuid = getuid();
112    /* -l, -u, -d require root priv and username argument */
113    if ((opt & OPT_lud) && (myuid || !argv[0]))
114        bb_show_usage();
115
116    /* Will complain and die if username not found */
117    myname = xstrdup(xuid2uname(myuid));
118    name = argv[0] ? argv[0] : myname;
119
120    pw = xgetpwnam(name);
121    if (myuid && pw->pw_uid != myuid) {
122        /* LOGMODE_BOTH */
123        bb_error_msg_and_die("%s can't change password for %s", myname, name);
124    }
125
126#if ENABLE_FEATURE_SHADOWPASSWDS
127    {
128        /* getspnam_r may return 0 yet set result to NULL.
129         * At least glibc 2.4 does this. Be extra paranoid here. */
130        struct spwd *result = NULL;
131        errno = 0;
132        if (getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result) != 0
133         || !result /* no error, but no record found either */
134         || strcmp(result->sp_namp, pw->pw_name) != 0 /* paranoia */
135        ) {
136            if (errno != ENOENT) {
137                /* LOGMODE_BOTH */
138                bb_perror_msg("no record of %s in %s, using %s",
139                    name, bb_path_shadow_file,
140                    bb_path_passwd_file);
141            }
142            /* else: /etc/shadow does not exist,
143             * apparently we are on a shadow-less system,
144             * no surprise there */
145        } else {
146            pw->pw_passwd = result->sp_pwdp;
147        }
148    }
149#endif
150
151    /* Decide what the new password will be */
152    newp = NULL;
153    c = pw->pw_passwd[0] - '!';
154    if (!(opt & OPT_lud)) {
155        if (myuid && !c) { /* passwd starts with '!' */
156            /* LOGMODE_BOTH */
157            bb_error_msg_and_die("can't change "
158                    "locked password for %s", name);
159        }
160        printf("Changing password for %s\n", name);
161        newp = new_password(pw, myuid, opt & STATE_ALGO_md5);
162        if (!newp) {
163            logmode = LOGMODE_STDIO;
164            bb_error_msg_and_die("password for %s is unchanged", name);
165        }
166    } else if (opt & OPT_lock) {
167        if (!c) goto skip; /* passwd starts with '!' */
168        newp = xasprintf("!%s", pw->pw_passwd);
169    } else if (opt & OPT_unlock) {
170        if (c) goto skip; /* not '!' */
171        /* pw->pw_passwd points to static storage,
172         * strdup'ing to avoid nasty surprizes */
173        newp = xstrdup(&pw->pw_passwd[1]);
174    } else if (opt & OPT_delete) {
175        //newp = xstrdup("");
176        newp = (char*)"";
177    }
178
179    rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * 30000;
180    setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
181    bb_signals(0
182        + (1 << SIGHUP)
183        + (1 << SIGINT)
184        + (1 << SIGQUIT)
185        , SIG_IGN);
186    umask(077);
187    xsetuid(0);
188
189#if ENABLE_FEATURE_SHADOWPASSWDS
190    filename = bb_path_shadow_file;
191    rc = update_passwd(bb_path_shadow_file, name, newp, NULL);
192    if (rc == 0) /* no lines updated, no errors detected */
193#endif
194    {
195        filename = bb_path_passwd_file;
196        rc = update_passwd(bb_path_passwd_file, name, newp, NULL);
197    }
198    /* LOGMODE_BOTH */
199    if (rc < 0)
200        bb_error_msg_and_die("can't update password file %s",
201                filename);
202    bb_info_msg("Password for %s changed by %s", name, myname);
203
204    //if (ENABLE_FEATURE_CLEAN_UP) free(newp);
205 skip:
206    if (!newp) {
207        bb_error_msg_and_die("password for %s is already %slocked",
208            name, (opt & OPT_unlock) ? "un" : "");
209    }
210    if (ENABLE_FEATURE_CLEAN_UP) free(myname);
211    return 0;
212}
Note: See TracBrowser for help on using the repository browser.