diff -u -r shadow-4.0.13/debian/changelog shadow-4.0.13-sudo-hint/debian/changelog --- shadow-4.0.13/debian/changelog 2006-02-03 10:42:51.000000000 +0000 +++ shadow-4.0.13-sudo-hint/debian/changelog 2006-02-03 06:03:45.000000000 +0000 @@ -1,3 +1,10 @@ +shadow (1:4.0.13-7ubuntu2) dapper; urgency=low + + * Add a hint to use 'sudo' the destination account is locked + (has a disabled/starred password) and the session is interactive. + + -- Paul Sladen Fri, 03 Feb 2006 06:03:39 +0000 + shadow (1:4.0.13-7ubuntu1) dapper; urgency=low * Resynchronise with Debian. diff -u -r shadow-4.0.13/debian/login.defs shadow-4.0.13-sudo-hint/debian/login.defs --- shadow-4.0.13/debian/login.defs 2006-02-03 10:42:51.000000000 +0000 +++ shadow-4.0.13-sudo-hint/debian/login.defs 2006-02-03 07:48:15.000000000 +0000 @@ -294,6 +294,15 @@ # #MD5_CRYPT_ENAB no +# +# Give users useful information about using 'sudo' if the account +# they are attempting to 'su' to is disabled and has no password set. + +SUDO_HINT_ENABLE yes +SUDO_HINT_MESSAGE "See: man su_sudo\nUse: " +SUDO_HINT_GROUP_CHECK yes +SUDO_HINT_GROUP "admin" + ################# OBSOLETED BY PAM ############## # # # These options are now handled by PAM. Please # diff -u -r shadow-4.0.13/lib/getdef.c shadow-4.0.13-sudo-hint/lib/getdef.c --- shadow-4.0.13/lib/getdef.c 2006-02-03 11:00:18.000000000 +0000 +++ shadow-4.0.13-sudo-hint/lib/getdef.c 2006-02-03 11:14:39.000000000 +0000 @@ -74,6 +74,10 @@ {"PASS_MAX_DAYS", NULL}, {"PASS_MIN_DAYS", NULL}, {"PASS_WARN_AGE", NULL}, + {"SUDO_HINT_ENABLE", NULL}, + {"SUDO_HINT_GROUP", NULL}, + {"SUDO_HINT_GROUP_CHECK", NULL}, + {"SUDO_HINT_MESSAGE", NULL}, {"SULOG_FILE", NULL}, {"SU_NAME", NULL}, {"TTYGROUP", NULL}, diff -u -r shadow-4.0.13/src/su.c shadow-4.0.13-sudo-hint/src/su.c --- shadow-4.0.13/src/su.c 2006-02-03 11:00:18.000000000 +0000 +++ shadow-4.0.13-sudo-hint/src/su.c 2006-02-03 11:05:56.000000000 +0000 @@ -178,6 +178,26 @@ exit (1); } +static int is_locked(const char *username) +{ + struct spwd *line = getspnam(username); + return (line && line->sp_pwdp + && (*line->sp_pwdp == '*' || *line->sp_pwdp == '!')); +} + +static int group_includes_user(const char *group_name, int uid) +{ + struct passwd *pw; + struct group *gr; + char *s; + pw = getpwuid(uid); + gr = getgrnam(group_name); + if(pw && gr) + for(s = *gr->gr_mem; s; s++) + if(!strncmp(pw->pw_name, s, 32)) + return 1; + return 0; +} #ifdef USE_PAM /* Signal handler for parent process later */ @@ -583,6 +603,46 @@ pwent = *pw; /* + * Hint the user that they might want to try 'sudo' instead: + * This requires: + * (1) ensure user is not yet root. + * (2) isatty() to check for interactive use + * (3) detect if destination_account is locked/starred. + * - can't get from pam_unix.so/pam_acct_mgmt()... + * - requires regex_match("^[*!]", shadow.getspnam("root")->sp_pwdp) + * + same as 'passwd --status root' + * (4) is the running user allowed to 'sudo' + * 4a cheap: check user is in group %admin + */ + + if(getdef_bool ("SUDO_HINT_ENABLE") + && (getuid() > 0) + && isatty(0) + && is_locked(name)) { + char *sudo_hint_message, *sudo_hint_group; + int check_group; + + if(check_group = getdef_bool("SUDO_HINT_GROUP_CHECK")) + if(!(sudo_hint_group = getdef_str ("SUDO_HINT_GROUP"))) + sudo_hint_group = "admin"; + + if(!check_group || group_includes_user(sudo_hint_group, getuid())) { + if(!(sudo_hint_message = getdef_str ("SUDO_HINT_MESSAGE"))) + sudo_hint_message = _("Use: "); + fputs(sudo_hint_message, stderr); + fputs("sudo ", stderr); + if(strcmp(name, "root") != 0) { + fputs(" -u ", stderr); + fputs(name, stderr); + } + fputs(command ? command : _(""), stderr); + fputs("\n", stderr); + exit(1); + } + /* Fall-through if our critera was not matched */ + } + + /* * If a new login is being set up, the old environment will be * ignored and a new one created later on. */