]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - login-utils/passwd.c
2 * passwd.c - change password on an account
4 * Initially written for Linux by Peter Orbaek <poe@daimi.aau.dk>
5 * Currently maintained at ftp://ftp.daimi.aau.dk/pub/linux/poe/
7 * Hacked by Alvaro Martinez Echevarria, alvaro@enano.etsit.upm.es,
8 * to allow peaceful coexistence with yp. Nov 94.
10 * Hacked to allow root to set passwd from command line.
11 * by Arpad Magossanyi (mag@tas.vein.hu)
15 * Sun Oct 15 13:18:34 1995 Martin Schulze <joey@finlandia.infodrom.north.de>
17 * I have completely rewritten the whole argument handling (what?)
18 * to support two things. First I wanted "passwd $user $pw" to
20 (a very bad idea; command lines are visible to people doing ps
21 or running a background job that just collects all command lines)
23 * work and second I wanted simplicity checks to be done for
24 * root, too. Only root can turn this off using the -f
25 * switch. Okay, I started with this to support -V version
26 * information, but one thing comes to the next. *sigh*
27 * In a later step perhaps we'll be able to support shadow
30 * I have also included a DEBUG mode (-DDEBUG) to test the
31 * argument handling _without_ any write attempt to
34 * If you're paranoid about security on your system, you may want
35 * to add -DLOGALL to CFLAGS. This will turn on additional syslog
36 * logging of every password change. (user changes are logged as
37 * auth.notice, but changing root's password is logged as
38 * auth.warning. (Of course, the password itself is not logged.)
41 /* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
42 * - added Native Language Support
43 * Sun Mar 21 1999 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
44 * - fixed strerr(errno) in gettext calls
48 * Usage: passwd [username [password]]
49 * Only root may use the one and two argument forms.
52 #include <sys/types.h>
66 #include <sys/resource.h>
72 # define _PATH_CHFN "/usr/bin/chfn"
73 # define _PATH_CHSH "/usr/bin/chsh"
82 extern int is_local(char *); /* islocal.c */
83 extern int setpwnam(struct passwd
*); /* setpwnam.c */
85 #define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.')
86 #define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
94 vfprintf(stderr
, str
, vlst
);
95 fprintf(stderr
, ": ");
102 * Do various checks for stupid passwords here...
104 * This would probably be the best place for checking against
108 int check_passwd_string(char *passwd
, char *string
)
114 /* test for string at the beginning of passwd */
115 for (p
= passwd
, q
= string
; *q
&& *p
; q
++, p
++) {
116 if(tolower(*p
) != tolower(*q
)) {
122 /* test for reverse string at the beginning of passwd */
123 for (p
= passwd
, q
= string
+ strlen(string
)-1;
124 *p
&& q
>= string
; p
++, q
--) {
125 if(tolower(*p
) != tolower(*q
)) {
131 /* test for string at the end of passwd */
132 for (p
= passwd
+ strlen(passwd
)-1, q
= string
+ strlen(string
)-1;
133 q
>= string
&& p
>= passwd
; q
--, p
--) {
134 if(tolower(*p
) != tolower(*q
)) {
140 /* test for reverse string at the beginning of passwd */
141 for (p
= passwd
+ strlen(passwd
)-1, q
= string
;
142 p
>= passwd
&& *q
; p
--, q
++) {
143 if(tolower(*p
) != tolower(*q
)) {
155 int check_passwd(char *passwd
, char *oldpasswd
, char *user
, char *gecos
)
157 int ucase
, lcase
, digit
, other
;
160 if ( (strlen(passwd
) < 6) ) {
161 printf(_("The password must have at least 6 characters, try again.\n"));
165 other
= digit
= ucase
= lcase
= 0;
166 for (p
= passwd
; *p
; p
++) {
167 ucase
= ucase
|| isupper(*p
);
168 lcase
= lcase
|| islower(*p
);
169 digit
= digit
|| isdigit(*p
);
170 other
= other
|| !isalnum(*p
);
173 if ( (other
+ digit
+ ucase
+ lcase
) < 2) {
174 printf(_("The password must contain characters out of two of the following\n"));
175 printf(_("classes: upper and lower case letters, digits and non alphanumeric\n"));
176 printf(_("characters. See passwd(1) for more information.\n"));
180 if ( oldpasswd
[0] && !strncmp(oldpasswd
, crypt(passwd
, oldpasswd
), 13) ) {
181 printf(_("You cannot reuse the old password.\n"));
185 if ( !check_passwd_string(passwd
, user
) ) {
186 printf(_("Please don't use something like your username as password!\n"));
190 /* check against realname */
191 if ( (c
= index(gecos
, ',')) ) {
192 if ( c
-gecos
&& (g
= (char *)malloc (c
-gecos
+1)) ) {
193 strncpy (g
, gecos
, c
-gecos
);
195 while ( (c
=rindex(g
, ' ')) ) {
196 if ( !check_passwd_string(passwd
, c
+1) ) {
197 printf(_("Please don't use something like your realname as password!\n"));
203 if ( !check_passwd_string(passwd
, g
) ) {
204 printf(_("Please don't use something like your realname as password!\n"));
213 * if ( !check_password_dict(passwd) ) ...
221 printf (_("Usage: passwd [username [password]]\n"));
222 printf(_("Only root may use the one and two argument forms.\n"));
231 uid_t gotuid
= getuid();
232 char *pwdstr
= NULL
, *cryptstr
, *oldstr
;
237 int force_passwd
= 0;
241 int fullname
= 0, shell
= 0;
242 static const struct option long_options
[] =
244 {"fullname", no_argument
, 0, 'f'},
245 {"shell", no_argument
, 0, 's'},
246 {"force", no_argument
, 0, 'o'},
247 {"quiet", no_argument
, 0, 'q'},
248 {"silent", no_argument
, 0, 'q'},
249 {"version", no_argument
, 0, 'v'},
254 setlocale(LC_ALL
, "");
255 bindtextdomain(PACKAGE
, LOCALEDIR
);
259 while ( (c
= getopt_long(argc
, argv
, "foqsvV", long_options
, &opt_index
)) != -1 ) {
275 printf("%s\n", util_linux_version
);
278 fprintf(stderr
, _("Usage: passwd [-foqsvV] [user [password]]\n"));
283 if (fullname
|| shell
) {
287 setuid(getuid()); /* drop special privs. */
289 args
[0] = _PATH_CHFN
;
291 args
[0] = _PATH_CHSH
;
293 for (i
= optind
, j
= 1; (i
< argc
) && (j
< 99); i
++, j
++)
297 execv(args
[0], args
);
299 fprintf(stderr
, _("Can't exec %s: %s\n"), args
[0], strerror(errsv
));
303 switch (argc
- optind
) {
305 /* Why use getlogin()? Some systems allow having several
306 usernames with the same uid, especially several root accounts.
307 One changes the password for the username, not the uid. */
308 if ( !(user
= getlogin()) || !*user
) {
309 if ( !(pe
= getpwuid( getuid() )) ) {
310 pexit(_("Cannot find login name"));
317 printf(_("Only root can change the password for others.\n"));
324 printf(_("Only root can change the password for others.\n"));
328 pwdstr
= argv
[optind
+1];
332 printf(_("Too many arguments.\n"));
336 if(!(pe
= getpwnam(user
))) {
337 pexit(_("Can't find username anywhere. Is `%s' really a user?"), user
);
340 if (!(is_local(user
))) {
341 puts(_("Sorry, I can only change local passwords. Use yppasswd instead."));
345 /* if somebody got into changing utmp... */
346 if(gotuid
&& gotuid
!= pe
->pw_uid
) {
347 puts(_("UID and username does not match, imposter!"));
352 printf( _("Changing password for %s\n"), user
);
354 if ( (gotuid
&& pe
->pw_passwd
&& pe
->pw_passwd
[0])
355 || (!gotuid
&& !strcmp(user
,"root")) ) {
356 oldstr
= getpass(_("Enter old password: "));
357 if(strncmp(pe
->pw_passwd
, crypt(oldstr
, pe
->pw_passwd
), 13)) {
358 puts(_("Illegal password, imposter."));
363 if ( pwdstr
) { /* already set on command line */
364 if ( !force_passwd
&& !check_passwd(pwdstr
, pe
->pw_passwd
, user
, pe
->pw_gecos
) )
367 /* password not set on command line by root, ask for it ... */
370 pwdstr
= getpass(_("Enter new password: "));
371 if (pwdstr
[0] == '\0') {
372 puts(_("Password not changed."));
376 if ( (gotuid
|| (!gotuid
&& !force_passwd
))
377 && !check_passwd(pwdstr
, pe
->pw_passwd
, user
, pe
->pw_gecos
) )
380 strncpy(pwdstr1
, pwdstr
, 9);
382 pwdstr
= getpass(_("Re-type new password: "));
384 if(strncmp(pwdstr
, pwdstr1
, 8)) {
385 puts(_("You misspelled it. Password not changed."));
388 } /* pwdstr i.e. password set on command line */
390 time(&tm
); tm
^= getpid();
391 salt
[0] = bin_to_ascii(tm
& 0x3f);
392 salt
[1] = bin_to_ascii((tm
>> 6) & 0x3f);
393 cryptstr
= crypt(pwdstr
, salt
);
395 if (pwdstr
[0] == 0) cryptstr
= "";
398 openlog("passwd", 0, LOG_AUTH
);
400 syslog(LOG_NOTICE
,_("password changed, user %s"),user
);
402 if ( !strcmp(user
, "root") )
403 syslog(LOG_WARNING
,_("ROOT PASSWORD CHANGED"));
405 syslog(LOG_NOTICE
,_("password changed by root, user %s"),user
);
410 pe
->pw_passwd
= cryptstr
;
412 printf (_("calling setpwnam to set password.\n"));
414 if (setpwnam( pe
) < 0) {
415 perror( "setpwnam" );
416 printf( _("Password *NOT* changed. Try again later.\n" ));
422 printf(_("Password changed.\n"));