struct spwd * pam_modutil_getspnam(pam_handle_t *pamh, const char *user) { #ifdef HAVE_GETSPNAM_R void *buffer=NULL; size_t length = PWD_INITIAL_LENGTH; do { int status; void *new_buffer; struct spwd *result = NULL; new_buffer = realloc(buffer, sizeof(struct spwd) + length); if (new_buffer == NULL) { D(("out of memory")); /* no memory for the user - so delete the memory */ if (buffer) { free(buffer); } return NULL; } buffer = new_buffer; /* make the re-entrant call to get the spwd structure */ errno = 0; status = getspnam_r(user, buffer, sizeof(struct spwd) + (char *) buffer, length, &result); if (!status && (result == buffer)) { char *data_name; const void *ignore; int i; data_name = malloc(strlen("_pammodutil_getspnam") + 1 + strlen(user) + 1 + intlen(INT_MAX) + 1); if ((pamh != NULL) && (data_name == NULL)) { D(("was unable to register the data item [%s]", pam_strerror(pamh, status))); free(buffer); return NULL; } if (pamh != NULL) { for (i = 0; i < INT_MAX; i++) { sprintf(data_name, "_pammodutil_getspnam_%s_%d", user, i); status = PAM_NO_MODULE_DATA; if (pam_get_data(pamh, data_name, &ignore) != PAM_SUCCESS) { status = pam_set_data(pamh, data_name, result, pam_modutil_cleanup); } if (status == PAM_SUCCESS) { break; } } } else { status = PAM_SUCCESS; } free(data_name); if (status == PAM_SUCCESS) { D(("success")); return result; } D(("was unable to register the data item [%s]", pam_strerror(pamh, status))); free(buffer); return NULL; } else if (errno != ERANGE && errno != EINTR) { /* no sense in repeating the call */ break; } length <<= PWD_LENGTH_SHIFT; } while (length < PWD_ABSURD_PWD_LENGTH); D(("spwd structure took %u bytes or so of memory", length+sizeof(struct spwd))); free(buffer); return NULL; #else /* ie. ifndef HAVE_GETSPNAM_R */ /* * Sorry, there does not appear to be a reentrant version of * getspnam(). So, we use the standard libc function. */ return getspnam(user); #endif /* def HAVE_GETSPNAM_R */ }
int main (int argc, char** argv) { /* define ip */ char *ip = "127.0.0.1"; /* check argument list */ if (3 > argc) { printf("Error: bad args\n",argv[0]); printf("Usage: %s user password [ip]\n",argv[0]); exit(1); }; /* check ip */ if (4 <= argc) { ip = (char*)malloc(strlen(argv[3])); strcpy(ip, argv[3]); } /* format current time */ time_t lt = time(NULL); struct tm* ptr = localtime(<); char str[280]; strftime(str, 100, "%Y-%m-%d %H:%M:%S ", ptr); /* open log file */ FILE* pFile = fopen ("/usr/local/vesta/log/auth.log","a+"); if (NULL == pFile) { printf("Error: can not open file %s \n", argv[0]); exit(12); } /* parse user argument */ struct passwd* userinfo = getpwnam(argv[1]); if (NULL != userinfo) { struct spwd* passw = getspnam(userinfo->pw_name); if (NULL != passw) { char* cryptedPasswrd = (char*)crypt(argv[2], passw->sp_pwdp); if (strcmp(passw->sp_pwdp,crypt(argv[2],passw->sp_pwdp))==0) { /* concatinate time with user and ip */ strcat(str, userinfo->pw_name); strcat(str, " "); strcat(str, ip); strcat(str, " successfully logged in \n"); fputs (str,pFile); /* write */ fclose (pFile); /* close */ exit(EXIT_SUCCESS); /* exit */ } else { /* concatinate time with user string */ printf ("Error: password missmatch\n"); strcat(str, userinfo->pw_name); strcat(str, " "); strcat(str, ip); strcat(str, " failed to login \n"); fputs (str,pFile); /* write */ fclose (pFile); /* close */ exit(9); /* exit */ }; } } else { printf("Error: no such user\n",argv[1]); exit(3); }; return EXIT_SUCCESS; };
int daemon_AuthUserPwd(char *username, char *password, char *errbuf) { #ifdef WIN32 /* Warning: the user which launches the process must have the SE_TCB_NAME right. This corresponds to have the "Act as part of the Operating System" turined on (administrative tools, local security settings, local policies, user right assignment) However, it seems to me that if you run it as a service, this right should be provided by default. */ HANDLE Token; if (LogonUser(username, ".", password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &Token) == 0) { int error; error = GetLastError(); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf, PCAP_ERRBUF_SIZE, NULL); return -1; } // This call should change the current thread to the selected user. // I didn't test it. if (ImpersonateLoggedOnUser(Token) == 0) { int error; error = GetLastError(); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf, PCAP_ERRBUF_SIZE, NULL); CloseHandle(Token); return -1; } CloseHandle(Token); return 0; #else /* Standard user authentication: http://www.unixpapa.com/incnote/passwd.html Problem: it is not able to merge the standard pwd file with the shadow one Shadow user authentication: http://www.tldp.org/HOWTO/Shadow-Password-HOWTO-8.html Problem: the program must either (1) run as root, or (2) run as user, but it must be owned by root and must be SUID root (chmod u+s rpcapd) */ struct passwd *user; #ifdef linux struct spwd *usersp; #endif // This call is needed to get the uid if ((user= getpwnam(username)) == NULL) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: no such user"); return -1; } #ifdef linux // This call is needed to get the password; otherwise 'x' is returned if ((usersp= getspnam(username)) == NULL) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: no such user"); return -1; } if (strcmp(usersp->sp_pwdp, (char *) crypt(password, usersp->sp_pwdp) ) != 0) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: password incorrect"); return -1; } #endif #ifdef bsd if (strcmp(user->pw_passwd, (char *) crypt(password, user->pw_passwd) ) != 0) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: password incorrect"); return -1; } #endif if (setuid(user->pw_uid) ) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s", pcap_strerror(errno) ); return -1; } /* if (setgid(user->pw_gid) ) { SOCK_ASSERT("setgid failed", 1); snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s", pcap_strerror(errno) ); return -1; } */ return 0; #endif }
static int _unix_verify_shadow(const char *user, unsigned int ctrl) { struct passwd *pwd = NULL; /* Password and shadow password */ struct spwd *spwdent = NULL; /* file entries for the user */ time_t curdays; int retval = PAM_SUCCESS; /* UNIX passwords area */ setpwent(); pwd = getpwnam(user); /* Get password file entry... */ endpwent(); if (pwd == NULL) return PAM_AUTHINFO_UNAVAIL; /* We don't need to do the rest... */ if (strcmp(pwd->pw_passwd, "x") == 0) { /* ...and shadow password file entry for this user, if shadowing is enabled */ setspent(); spwdent = getspnam(user); endspent(); if (spwdent == NULL) return PAM_AUTHINFO_UNAVAIL; } else { if (strcmp(pwd->pw_passwd,"*NP*") == 0) { /* NIS+ */ uid_t save_uid; save_uid = geteuid(); seteuid (pwd->pw_uid); spwdent = getspnam( user ); seteuid (save_uid); if (spwdent == NULL) return PAM_AUTHINFO_UNAVAIL; } else spwdent = NULL; } if (spwdent != NULL) { /* We have the user's information, now let's check if their account has expired (60 * 60 * 24 = number of seconds in a day) */ if (off(UNIX__IAMROOT, ctrl)) { /* Get the current number of days since 1970 */ curdays = time(NULL) / (60 * 60 * 24); if ((curdays < (spwdent->sp_lstchg + spwdent->sp_min)) && (spwdent->sp_min != -1)) retval = PAM_AUTHTOK_ERR; else if ((curdays > (spwdent->sp_lstchg + spwdent->sp_max + spwdent->sp_inact)) && (spwdent->sp_max != -1) && (spwdent->sp_inact != -1) && (spwdent->sp_lstchg != 0)) /* * Their password change has been put off too long, */ retval = PAM_ACCT_EXPIRED; else if ((curdays > spwdent->sp_expire) && (spwdent->sp_expire != -1) && (spwdent->sp_lstchg != 0)) /* * OR their account has just plain expired */ retval = PAM_ACCT_EXPIRED; } } return retval; }
int vsf_sysdep_check_auth(struct mystr* p_user_str, const struct mystr* p_pass_str, const struct mystr* p_remote_host) { /* Padavan */ (void) p_remote_host; return asus_check_auth(p_user_str, p_pass_str); #if 0 const char* p_crypted; const struct passwd* p_pwd = getpwnam(str_getbuf(p_user_str)); (void) p_remote_host; if (p_pwd == NULL) { return 0; } #ifdef VSF_SYSDEP_HAVE_USERSHELL if (tunable_check_shell) { const char* p_shell; while ((p_shell = getusershell()) != NULL) { if (!vsf_sysutil_strcmp(p_shell, p_pwd->pw_shell)) { break; } } endusershell(); if (p_shell == NULL) { return 0; } } #endif #ifdef VSF_SYSDEP_HAVE_SHADOW { const struct spwd* p_spwd = getspnam(str_getbuf(p_user_str)); if (p_spwd != NULL) { long curr_time = vsf_sysutil_get_time_sec(); int days; days = curr_time / (60 * 60 * 24); if (p_spwd->sp_expire > 0 && p_spwd->sp_expire < days) { return 0; } if (p_spwd->sp_lstchg > 0 && p_spwd->sp_max > 0 && p_spwd->sp_lstchg + p_spwd->sp_max < days) { return 0; } p_crypted = crypt(str_getbuf(p_pass_str), p_spwd->sp_pwdp); if (!vsf_sysutil_strcmp(p_crypted, p_spwd->sp_pwdp)) { return 1; } } } #endif /* VSF_SYSDEP_HAVE_SHADOW */ p_crypted = crypt(str_getbuf(p_pass_str), p_pwd->pw_passwd); if (!vsf_sysutil_strcmp(p_crypted, p_pwd->pw_passwd)) { return 1; } return 0; #endif }
int main(int argc, char* argv[]) { char *username, *password, *encrypted, *p; struct passwd *pwd; struct spwd *spwd; int authOK; long lnmax; size_t len; // {{{ 1. get username lnmax = sysconf(_SC_LOGIN_NAME_MAX); if(lnmax == -1) lnmax = 256; if((username = malloc(lnmax)) == NULL) { perror("malloc() error"); exit(EXIT_FAILURE); } printf("Username: "******"Not found %s\n", username); else perror("getpwnam() error"); exit(EXIT_FAILURE); } // get record form /etc/shadow if((spwd = getspnam(username)) == NULL) { if(errno == EACCES) perror("no permission to read shadow password file"); else perror("getspnam() error"); exit(EXIT_FAILURE); } pwd->pw_passwd = spwd->sp_pwdp; // use the shadow password //}}} // {{{ 3. get password and encrypt, then verify; // 读取密码后,应立即加密,并尽快将密码的明文从内存中抹去,以防恶意之徒借程序崩溃之机,读取内核转储文件以获取密码; password = getpass("Password: "******"crypt() error"); exit(EXIT_FAILURE); } /*printf("sp_pwdp: %s\n", spwd->sp_pwdp);*/ /*printf("encrypted:%s\n", encrypted);*/ authOK = (strcmp(encrypted, pwd->pw_passwd) == 0); if(authOK == 0) { printf("Incorrect password\n"); exit(EXIT_FAILURE); } printf("Successfully authenticated: UID=%ld\n", (long)pwd->pw_uid); //}}} // Now do authenticated work ... return 0; }
// getrootpwent.cmt static struct passwd *getrootpwent(int try_manually) { static struct passwd pwd; struct passwd *pw; struct spwd *spw; FILE *fp; static char line[256]; static char sline[256]; char *p; /* * First, we try to get the password the standard * way using normal library calls. */ if ((pw = getpwnam("root")) && !strcmp(pw->pw_passwd, "x") && (spw = getspnam("root"))) pw->pw_passwd = spw->sp_pwdp; if (pw || !try_manually) return pw; /* * If we come here, we could not retrieve the root * password through library calls and we try to * read the password and shadow files manually. */ pwd.pw_name = "root"; pwd.pw_passwd = ""; pwd.pw_gecos = "Super User"; pwd.pw_dir = "/"; pwd.pw_shell = ""; pwd.pw_uid = 0; pwd.pw_gid = 0; if ((fp = fopen(F_PASSWD, "r")) == NULL) { perror(F_PASSWD); return &pwd; } /* * Find root in the password file. */ while((p = fgets(line, 256, fp)) != NULL) { if (strncmp(line, "root:", 5) != 0) continue; p += 5; set(&pwd.pw_passwd, strsep(&p, ":")); (void)strsep(&p, ":"); (void)strsep(&p, ":"); set(&pwd.pw_gecos, strsep(&p, ":")); set(&pwd.pw_dir, strsep(&p, ":")); set(&pwd.pw_shell, strsep(&p, "\n")); p = line; break; } fclose(fp); /* * If the encrypted password is valid * or not found, return. */ if (p == NULL) { fprintf(stderr, "%s: no entry for root\n", F_PASSWD); return &pwd; } if (valid(pwd.pw_passwd)) return &pwd; /* * The password is invalid. If there is a * shadow password, try it. */ strcpy(pwd.pw_passwd, ""); if ((fp = fopen(F_SHADOW, "r")) == NULL) { fprintf(stderr, "%s: root password garbled\n", F_PASSWD); return &pwd; } while((p = fgets(sline, 256, fp)) != NULL) { if (strncmp(sline, "root:", 5) != 0) continue; p += 5; set(&pwd.pw_passwd, strsep(&p, ":")); break; } fclose(fp); /* * If the password is still invalid, * NULL it, and return. */ if (p == NULL) { fprintf(stderr, "%s: no entry for root\n", F_SHADOW); strcpy(pwd.pw_passwd, ""); } if (!valid(pwd.pw_passwd)) { fprintf(stderr, "%s: root password garbled\n", F_SHADOW); strcpy(pwd.pw_passwd, ""); } return &pwd; }
INT PasswdMain ( INT ArgumentCount, CHAR **Arguments ) /*++ Routine Description: This routine is the main entry point for the passwd utility. Arguments: ArgumentCount - Supplies the number of command line arguments the program was invoked with. Arguments - Supplies a tokenized array of command line arguments. Return Value: Returns an integer exit code. 0 for success, nonzero otherwise. --*/ { PSTR Algorithm; PPASSWD_ALGORITHM AlgorithmEntry; ULONG ArgumentIndex; size_t Length; struct spwd LocalShadow; PSTR NewPassword; PSTR OldPassword; INT Option; ULONG Options; PSTR RootDirectory; struct spwd *Shadow; UPDATE_PASSWORD_OPERATION ShadowOperation; int Status; PSTR ThisUserName; int TotalStatus; struct passwd *User; uid_t UserId; PSTR UserName; Algorithm = PASSWD_DEFAULT_ALGORITHM; NewPassword = NULL; Options = 0; RootDirectory = NULL; ShadowOperation = UpdatePasswordUpdateLine; ThisUserName = NULL; TotalStatus = 0; UserName = NULL; // // Process the control arguments. // while (TRUE) { Option = getopt_long(ArgumentCount, Arguments, PASSWD_OPTIONS_STRING, PasswdLongOptions, NULL); if (Option == -1) { break; } if ((Option == '?') || (Option == ':')) { Status = 1; goto MainEnd; } switch (Option) { // // Select a new password hashing algorithm. // case 'A': if (strcasecmp(optarg, "des") == 0) { SwPrintError(0, NULL, "The DES algorithm has been deprecated"); Status = 1; goto MainEnd; } AlgorithmEntry = &(SwPasswordAlgorithms[0]); while (AlgorithmEntry->Name != NULL) { if (strcasecmp(optarg, AlgorithmEntry->Name) == 0) { Algorithm = AlgorithmEntry->Id; break; } AlgorithmEntry += 1; } if (AlgorithmEntry->Name == NULL) { SwPrintError(0, optarg, "Unknown algorithm"); Status = 1; goto MainEnd; } break; case 'd': Options |= PASSWD_OPTION_DELETE; break; case 'l': Options |= PASSWD_OPTION_LOCK; Options &= ~PASSWD_OPTION_UNLOCK; break; case 'R': RootDirectory = optarg; break; case 'u': Options |= PASSWD_OPTION_UNLOCK; Options &= ~PASSWD_OPTION_LOCK; break; case 'V': SwPrintVersion(PASSWD_VERSION_MAJOR, PASSWD_VERSION_MINOR); return 1; case 'H': printf(PASSWD_USAGE); return 1; default: assert(FALSE); Status = 1; goto MainEnd; } } ArgumentIndex = optind; if (ArgumentIndex > ArgumentCount) { ArgumentIndex = ArgumentCount; } // // Chroot if requested. Warm up libcrypt in case it's not in the chrooted // environment. // if (RootDirectory != NULL) { SwCrypt(NULL, NULL); Status = chroot(RootDirectory); if (Status != 0) { Status = errno; SwPrintError(Status, RootDirectory, "Failed to chroot"); goto MainEnd; } Status = chdir("/"); if (Status != 0) { Status = errno; SwPrintError(Status, RootDirectory, "Failed to chdir"); goto MainEnd; } } if (ArgumentIndex < ArgumentCount) { UserName = Arguments[ArgumentIndex]; ArgumentIndex += 1; } if (ArgumentIndex != ArgumentCount) { SwPrintError(0, NULL, "Unexpected additional arguments"); return 1; } openlog("passwd", 0, LOG_AUTH); UserId = getuid(); // // Only root can delete, lock, or unlock a password. // if (UserId != 0) { if ((Options & PASSWD_OPTIONS_ROOT) != 0) { SwPrintError(0, NULL, "-l, -u, and -d require root privileges"); Status = 1; goto MainEnd; } } // // Get the current user's name. // User = getpwuid(UserId); if (User == NULL) { SwPrintError(0, NULL, "User %ld not found", (long int)UserId); Status = ENOENT; goto MainEnd; } ThisUserName = strdup(User->pw_name); if (ThisUserName == NULL) { Status = ENOMEM; goto MainEnd; } // // If the user specified a login name on the command line, get that one. // if (UserName != NULL) { User = getpwnam(UserName); } // // The user can only change their own password, except for the superuser. // if ((UserId != 0) && (User->pw_uid != UserId)) { PasswdLogMessage(LOG_WARNING, "passwd: User %s cannot change password for " "account %s", ThisUserName, User->pw_name); Status = EPERM; goto MainEnd; } // // Get the shadow data. // errno = 0; Shadow = getspnam(User->pw_name); if ((Shadow == NULL) && (errno != ENOENT)) { Status = errno; PasswdLogMessage(LOG_WARNING, "passwd: warning: No shadow record of user %s, " "creating one", User->pw_name, strerror(Status)); memcpy(&LocalShadow, &SwShadowTemplate, sizeof(struct spwd)); LocalShadow.sp_namp = User->pw_name; LocalShadow.sp_lstchg = time(NULL) / (3600 * 24); Shadow = &LocalShadow; ShadowOperation = UpdatePasswordAddLine; } if (Shadow != NULL) { OldPassword = Shadow->sp_pwdp; } else { OldPassword = User->pw_passwd; } // // Potentially lock the password. // if ((Options & PASSWD_OPTION_LOCK) != 0) { if (OldPassword[0] != '!') { Length = strlen(OldPassword) + 2; NewPassword = malloc(Length); if (NewPassword != NULL) { NewPassword[0] = '!'; strncpy(NewPassword + 1, OldPassword, Length - 1); } } // // Potentially unlock the password. // } else if ((Options & PASSWD_OPTION_UNLOCK) != 0) { if (OldPassword[0] == '!') { NewPassword = strdup(OldPassword + 1); } } else if ((Options & PASSWD_OPTION_DELETE) != 0) { NewPassword = strdup(""); // // This is not a lock, unlock, or delete, just a regular password change. // } else { if ((UserId != 0) && (OldPassword[0] == '!')) { PasswdLogMessage(LOG_WARNING, "passwd: Cannot change password for %s: " "Account locked", User->pw_name); Status = EPERM; goto MainEnd; } NewPassword = PasswdGetNewPassword(User, Shadow, UserId, Algorithm); } if (NewPassword == NULL) { SwPrintError(0, NULL, "passwd: Password for %s is unchanged", User->pw_name); Status = 1; goto MainEnd; } if (Shadow != NULL) { Shadow->sp_pwdp = NewPassword; User->pw_passwd = PASSWORD_SHADOWED; Shadow->sp_lstchg = time(NULL) / (3600 * 24); } else { User->pw_passwd = NewPassword; } Status = SwUpdatePasswordLine(User, Shadow, ShadowOperation); if (Status < 0) { PasswdLogMessage(LOG_ERR, "passwd: Unable to change password for %s: %s", User->pw_name, strerror(Status)); } else { PasswdLogMessage(LOG_NOTICE, "passwd: Password changed for user %s", User->pw_name); } MainEnd: closelog(); if (NewPassword != NULL) { memset(NewPassword, 0, strlen(NewPassword)); free(NewPassword); } if (ThisUserName != NULL) { free(ThisUserName); } if ((TotalStatus == 0) && (Status != 0)) { TotalStatus = Status; } return TotalStatus; }
/* * process_flags - perform command line argument setting * * process_flags() interprets the command line arguments and sets the * values that the user will be created with accordingly. The values * are checked for sanity. */ static void process_flags (int argc, char **argv) { const struct group *grp; const struct passwd *pwd; const struct spwd *spwd = NULL; int anyflag = 0; int arg; if (argc == 1 || argv[argc - 1][0] == '-') usage (); if (!(pwd = getpwnam (argv[argc - 1]))) { fprintf (stderr, _("%s: user %s does not exist\n"), Prog, argv[argc - 1]); exit (E_NOTFOUND); } user_name = argv[argc - 1]; user_id = pwd->pw_uid; user_gid = pwd->pw_gid; user_comment = xstrdup (pwd->pw_gecos); user_home = xstrdup (pwd->pw_dir); user_shell = xstrdup (pwd->pw_shell); #ifdef WITH_AUDIT user_newname = user_name; user_newid = user_id; user_newgid = user_gid; user_newcomment = user_comment; user_newhome = user_home; user_newshell = user_shell; #endif #ifdef USE_NIS /* * Now make sure it isn't an NIS user. */ if (__ispwNIS ()) { char *nis_domain; char *nis_master; fprintf (stderr, _("%s: user %s is a NIS user\n"), Prog, user_name); if (!yp_get_default_domain (&nis_domain) && !yp_master (nis_domain, "passwd.byname", &nis_master)) { fprintf (stderr, _("%s: %s is the NIS master\n"), Prog, nis_master); } exit (E_NOTFOUND); } #endif if (is_shadow_pwd && (spwd = getspnam (user_name))) { user_expire = spwd->sp_expire; user_inactive = spwd->sp_inact; #ifdef WITH_AUDIT user_newexpire = user_expire; user_newinactive = user_inactive; #endif } { /* * Parse the command line options. */ int c; static struct option long_options[] = { {"append", required_argument, NULL, 'a'}, {"comment", required_argument, NULL, 'c'}, {"home", required_argument, NULL, 'd'}, {"expiredate", required_argument, NULL, 'e'}, {"inactive", required_argument, NULL, 'f'}, {"gid", required_argument, NULL, 'g'}, {"groups", required_argument, NULL, 'G'}, {"help", no_argument, NULL, 'h'}, {"login", required_argument, NULL, 'l'}, {"lock", no_argument, NULL, 'L'}, {"move-home", no_argument, NULL, 'm'}, {"non-unique", no_argument, NULL, 'o'}, {"password", required_argument, NULL, 'p'}, {"shell", required_argument, NULL, 's'}, {"uid", required_argument, NULL, 'u'}, {"unlock", no_argument, NULL, 'U'}, {NULL, 0, NULL, '\0'} }; while ((c = getopt_long (argc, argv, "ac:d:e:f:g:G:l:Lmop:s:u:U", long_options, NULL)) != -1) { switch (c) { case 'a': aflg++; break; case 'c': if (!VALID (optarg)) { fprintf (stderr, _("%s: invalid field `%s'\n"), Prog, optarg); exit (E_BAD_ARG); } #ifdef WITH_AUDIT user_newcomment = optarg; #else user_comment = optarg; #endif cflg++; break; case 'd': if (!VALID (optarg)) { fprintf (stderr, _("%s: invalid field `%s'\n"), Prog, optarg); exit (E_BAD_ARG); } dflg++; user_newhome = optarg; break; case 'e': if (*optarg) { #ifdef WITH_AUDIT user_newexpire = strtoday (optarg); if (user_newexpire == -1) { #else user_expire = strtoday (optarg); if (user_expire == -1) { #endif fprintf (stderr, _ ("%s: invalid date `%s'\n"), Prog, optarg); exit (E_BAD_ARG); } #ifdef WITH_AUDIT user_newexpire *= DAY / SCALE; #else user_expire *= DAY / SCALE; #endif } else #ifdef WITH_AUDIT user_newexpire = -1; #else user_expire = -1; #endif eflg++; break; case 'f': #ifdef WITH_AUDIT user_newinactive = get_number (optarg); #else user_inactive = get_number (optarg); #endif fflg++; break; case 'g': grp = getgr_nam_gid (optarg); if (!grp) { fprintf (stderr, _("%s: unknown group %s\n"), Prog, optarg); exit (E_NOTFOUND); } user_newgid = grp->gr_gid; gflg++; break; case 'G': if (get_groups (optarg)) exit (E_NOTFOUND); Gflg++; break; case 'l': if (!check_user_name (optarg)) { fprintf (stderr, _("%s: invalid field `%s'\n"), Prog, optarg); exit (E_BAD_ARG); } /* * If the name does not really change, we mustn't * set the flag as this will cause rather serious * problems later! */ if (strcmp (user_name, optarg)) lflg++; user_newname = optarg; break; case 'L': if (Uflg || pflg) usage (); Lflg++; break; case 'm': if (!dflg) usage (); mflg++; break; case 'o': if (!uflg) usage (); oflg++; break; case 'p': if (Lflg || Uflg) usage (); user_pass = optarg; pflg++; break; case 's': if (!VALID (optarg)) { fprintf (stderr, _("%s: invalid field `%s'\n"), Prog, optarg); exit (E_BAD_ARG); } #ifdef WITH_AUDIT user_newshell = optarg; #else user_shell = optarg; #endif sflg++; break; case 'u': user_newid = get_id (optarg); uflg++; break; case 'U': if (Lflg && pflg) usage (); Uflg++; break; default: usage (); } anyflag++; } } if (anyflag == 0) { fprintf (stderr, _("%s: no flags given\n"), Prog); exit (E_USAGE); } if (!is_shadow_pwd && (eflg || fflg)) { fprintf (stderr, _ ("%s: shadow passwords required for -e and -f\n"), Prog); exit (E_USAGE); } if (optind != argc - 1) usage (); if (aflg && (!Gflg)) { fprintf (stderr, _("%s: -a flag is ONLY allowed with the -G flag\n"), Prog); usage (); exit (E_USAGE); } if (dflg && strcmp (user_home, user_newhome) == 0) dflg = mflg = 0; if (uflg && user_id == user_newid) uflg = oflg = 0; if (lflg && getpwnam (user_newname)) { fprintf (stderr, _("%s: user %s exists\n"), Prog, user_newname); exit (E_NAME_IN_USE); } if (uflg && !oflg && getpwuid (user_newid)) { fprintf (stderr, _("%s: uid %lu is not unique\n"), Prog, (unsigned long) user_newid); exit (E_UID_IN_USE); } } /* * close_files - close all of the files that were opened * * close_files() closes all of the files that were opened for this new * user. This causes any modified entries to be written out. */ static void close_files (void) { if (!pw_close ()) { fprintf (stderr, _("%s: cannot rewrite password file\n"), Prog); fail_exit (E_PW_UPDATE); } if (is_shadow_pwd && !spw_close ()) { fprintf (stderr, _("%s: cannot rewrite shadow password file\n"), Prog); fail_exit (E_PW_UPDATE); } if (is_shadow_pwd) spw_unlock (); (void) pw_unlock (); /* * Close the DBM and/or flat files */ endpwent (); endspent (); endgrent (); #ifdef SHADOWGRP endsgent (); #endif } /* * open_files - lock and open the password files * * open_files() opens the two password files. */ static void open_files (void) { if (!pw_lock ()) { fprintf (stderr, _("%s: unable to lock password file\n"), Prog); exit (E_PW_UPDATE); } if (!pw_open (O_RDWR)) { fprintf (stderr, _("%s: unable to open password file\n"), Prog); fail_exit (E_PW_UPDATE); } if (is_shadow_pwd && !spw_lock ()) { fprintf (stderr, _("%s: cannot lock shadow password file\n"), Prog); fail_exit (E_PW_UPDATE); } if (is_shadow_pwd && !spw_open (O_RDWR)) { fprintf (stderr, _("%s: cannot open shadow password file\n"), Prog); fail_exit (E_PW_UPDATE); } } /* * usr_update - create the user entries * * usr_update() creates the password file entries for this user and * will update the group entries if required. */ static void usr_update (void) { struct passwd pwent; const struct passwd *pwd; struct spwd spent; const struct spwd *spwd = NULL; /* * Locate the entry in /etc/passwd, which MUST exist. */ pwd = pw_locate (user_name); if (!pwd) { fprintf (stderr, _("%s: %s not found in /etc/passwd\n"), Prog, user_name); fail_exit (E_NOTFOUND); } pwent = *pwd; new_pwent (&pwent); /* * Locate the entry in /etc/shadow. It doesn't have to exist, and * won't be created if it doesn't. */ if (is_shadow_pwd && (spwd = spw_locate (user_name))) { spent = *spwd; new_spent (&spent); } if (lflg || uflg || gflg || cflg || dflg || sflg || pflg || Lflg || Uflg) { if (!pw_update (&pwent)) { fprintf (stderr, _("%s: error changing password entry\n"), Prog); fail_exit (E_PW_UPDATE); } if (lflg && !pw_remove (user_name)) { fprintf (stderr, _("%s: error removing password entry\n"), Prog); fail_exit (E_PW_UPDATE); } } if (spwd && (lflg || eflg || fflg || pflg || Lflg || Uflg)) { if (!spw_update (&spent)) { fprintf (stderr, _ ("%s: error adding new shadow password entry\n"), Prog); fail_exit (E_PW_UPDATE); } if (lflg && !spw_remove (user_name)) { fprintf (stderr, _ ("%s: error removing shadow password entry\n"), Prog); fail_exit (E_PW_UPDATE); } } } /* * move_home - move the user's home directory * * move_home() moves the user's home directory to a new location. The * files will be copied if the directory cannot simply be renamed. */ static void move_home (void) { struct stat sb; if (mflg && stat (user_home, &sb) == 0) { /* * Don't try to move it if it is not a directory * (but /dev/null for example). --marekm */ if (!S_ISDIR (sb.st_mode)) return; if (access (user_newhome, F_OK) == 0) { fprintf (stderr, _("%s: directory %s exists\n"), Prog, user_newhome); fail_exit (E_HOMEDIR); } else if (rename (user_home, user_newhome)) { if (errno == EXDEV) { if (mkdir (user_newhome, sb.st_mode & 0777)) { fprintf (stderr, _ ("%s: can't create %s\n"), Prog, user_newhome); } if (chown (user_newhome, sb.st_uid, sb.st_gid)) { fprintf (stderr, _("%s: can't chown %s\n"), Prog, user_newhome); rmdir (user_newhome); fail_exit (E_HOMEDIR); } if (copy_tree (user_home, user_newhome, uflg ? user_newid : -1, gflg ? user_newgid : -1) == 0) { if (remove_tree (user_home) != 0 || rmdir (user_home) != 0) fprintf (stderr, _ ("%s: warning: failed to completely remove old home directory %s"), Prog, user_home); #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "moving home directory", user_newname, user_newid, 1); #endif return; } (void) remove_tree (user_newhome); (void) rmdir (user_newhome); } fprintf (stderr, _ ("%s: cannot rename directory %s to %s\n"), Prog, user_home, user_newhome); fail_exit (E_HOMEDIR); } #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "moving home directory", user_newname, user_newid, 1); #endif } if (uflg || gflg) { #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing home directory owner", user_newname, user_newid, 1); #endif chown (dflg ? user_newhome : user_home, uflg ? user_newid : user_id, gflg ? user_newgid : user_gid); } } /* * update_files - update the lastlog and faillog files */ static void update_files (void) { struct lastlog ll; struct faillog fl; int fd; /* * Relocate the "lastlog" entries for the user. The old entry is * left alone in case the UID was shared. It doesn't hurt anything * to just leave it be. */ if ((fd = open (LASTLOG_FILE, O_RDWR)) != -1) { lseek (fd, (off_t) user_id * sizeof ll, SEEK_SET); if (read (fd, (char *) &ll, sizeof ll) == sizeof ll) { lseek (fd, (off_t) user_newid * sizeof ll, SEEK_SET); write (fd, (char *) &ll, sizeof ll); } close (fd); } /* * Relocate the "faillog" entries in the same manner. */ if ((fd = open (FAILLOG_FILE, O_RDWR)) != -1) { lseek (fd, (off_t) user_id * sizeof fl, SEEK_SET); if (read (fd, (char *) &fl, sizeof fl) == sizeof fl) { lseek (fd, (off_t) user_newid * sizeof fl, SEEK_SET); write (fd, (char *) &fl, sizeof fl); } close (fd); } } #ifndef NO_MOVE_MAILBOX /* * This is the new and improved code to carefully chown/rename the user's * mailbox. Maybe I am too paranoid but the mail spool dir sometimes * happens to be mode 1777 (this makes mail user agents work without * being setgid mail, but is NOT recommended; they all should be fixed * to use movemail). --marekm */ static void move_mailbox (void) { const char *maildir; char mailfile[1024], newmailfile[1024]; int fd; struct stat st; maildir = getdef_str ("MAIL_DIR"); #ifdef MAIL_SPOOL_DIR if (!maildir && !getdef_str ("MAIL_FILE")) maildir = MAIL_SPOOL_DIR; #endif if (!maildir) return; /* * O_NONBLOCK is to make sure open won't hang on mandatory locks. * We do fstat/fchown to make sure there are no races (someone * replacing /var/spool/mail/luser with a hard link to /etc/passwd * between stat and chown). --marekm */ snprintf (mailfile, sizeof mailfile, "%s/%s", maildir, user_name); fd = open (mailfile, O_RDONLY | O_NONBLOCK, 0); if (fd < 0) { /* no need for warnings if the mailbox doesn't exist */ if (errno != ENOENT) perror (mailfile); return; } if (fstat (fd, &st) < 0) { perror ("fstat"); close (fd); return; } if (st.st_uid != user_id) { /* better leave it alone */ fprintf (stderr, _("%s: warning: %s not owned by %s\n"), Prog, mailfile, user_name); close (fd); return; } if (uflg) { if (fchown (fd, user_newid, (gid_t) - 1) < 0) { perror (_("failed to change mailbox owner")); } #ifdef WITH_AUDIT else { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing mail file owner", user_newname, user_newid, 1); } #endif } close (fd); if (lflg) { snprintf (newmailfile, sizeof newmailfile, "%s/%s", maildir, user_newname); if (link (mailfile, newmailfile) || unlink (mailfile)) { perror (_("failed to rename mailbox")); } #ifdef WITH_AUDIT else { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing mail file name", user_newname, user_newid, 1); } #endif } } #endif /* * main - usermod command */ int main (int argc, char **argv) { int grp_err = 0; #ifdef USE_PAM pam_handle_t *pamh = NULL; struct passwd *pampw; int retval; #endif #ifdef WITH_AUDIT audit_help_open (); #endif /* * Get my name so that I can use it to report errors. */ Prog = Basename (argv[0]); setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); sys_ngroups = sysconf (_SC_NGROUPS_MAX); user_groups = malloc ((1 + sys_ngroups) * sizeof (char *)); user_groups[0] = (char *) 0; OPENLOG ("usermod"); is_shadow_pwd = spw_file_present (); #ifdef SHADOWGRP is_shadow_grp = sgr_file_present (); #endif process_flags (argc, argv); #ifdef USE_PAM retval = PAM_SUCCESS; pampw = getpwuid (getuid ()); if (pampw == NULL) { retval = PAM_USER_UNKNOWN; } if (retval == PAM_SUCCESS) { retval = pam_start ("usermod", pampw->pw_name, &conv, &pamh); } if (retval == PAM_SUCCESS) { retval = pam_authenticate (pamh, 0); if (retval != PAM_SUCCESS) { pam_end (pamh, retval); } } if (retval == PAM_SUCCESS) { retval = pam_acct_mgmt (pamh, 0); if (retval != PAM_SUCCESS) { pam_end (pamh, retval); } } if (retval != PAM_SUCCESS) { fprintf (stderr, _("%s: PAM authentication failed\n"), Prog); exit (1); } #endif /* USE_PAM */ /* * Do the hard stuff - open the files, change the user entries, * change the home directory, then close and update the files. */ open_files (); usr_update (); nscd_flush_cache ("passwd"); nscd_flush_cache ("group"); close_files (); if (Gflg || lflg) grp_err = grp_update (); if (mflg) move_home (); #ifndef NO_MOVE_MAILBOX if (lflg || uflg) move_mailbox (); #endif if (uflg) { update_files (); /* * Change the UID on all of the files owned by `user_id' to * `user_newid' in the user's home directory. */ chown_tree (dflg ? user_newhome : user_home, user_id, user_newid, user_gid, gflg ? user_newgid : user_gid); } if (grp_err) exit (E_GRP_UPDATE); #ifdef USE_PAM if (retval == PAM_SUCCESS) pam_end (pamh, PAM_SUCCESS); #endif /* USE_PAM */ exit (E_SUCCESS); /* NOT REACHED */ }
static int #if defined(USE_PAM) || defined(_AIX) isNoPassAllowed( const char *un ) { struct passwd *pw = 0; # ifdef HAVE_GETSPNAM /* (sic!) - not USESHADOW */ struct spwd *spw; # endif #else isNoPassAllowed( const char *un, struct passwd *pw ) { #endif struct group *gr; char **fp; int hg; if (!*un) return 0; if (cursource != PWSRC_MANUAL) return 1; for (hg = 0, fp = td->noPassUsers; *fp; fp++) if (**fp == '@') hg = 1; else if (!strcmp( un, *fp )) return 1; else if (!strcmp( "*", *fp )) { #if defined(USE_PAM) || defined(_AIX) if (!(pw = getpwnam( un ))) return 0; if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*') continue; # ifdef HAVE_GETSPNAM /* (sic!) - not USESHADOW */ if ((spw = getspnam( un )) && (spw->sp_pwdp[0] == '!' || spw->sp_pwdp[0] == '*')) continue; # endif #endif if (pw->pw_uid) return 1; } #if defined(USE_PAM) || defined(_AIX) if (hg && (pw || (pw = getpwnam( un )))) { #else if (hg) { #endif for (setgrent(); (gr = getgrent()); ) for (fp = td->noPassUsers; *fp; fp++) if (**fp == '@' && !strcmp( gr->gr_name, *fp + 1 )) { if (pw->pw_gid == gr->gr_gid) { endgrent(); return 1; } for (; *gr->gr_mem; gr->gr_mem++) if (!strcmp( un, *gr->gr_mem )) { endgrent(); return 1; } } endgrent(); } return 0; } #if !defined(USE_PAM) && !defined(_AIX) && defined(HAVE_SETUSERCONTEXT) # define LC_RET0 do { login_close(lc); return 0; } while(0) #else # define LC_RET0 return 0 #endif int verify( GConvFunc gconv, int rootok ) { #ifdef USE_PAM const char *psrv; struct pam_data pdata; int pretc, pnopass; char psrvb[64]; #elif defined(_AIX) char *msg, *curret; int i, reenter; #else struct stat st; const char *nolg; char *buf; int fd; # ifdef HAVE_GETUSERSHELL char *s; # endif # if defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || defined(USESHADOW) int tim, expir, warntime, quietlog; # endif #endif debug( "verify ...\n" ); #ifdef USE_PAM pnopass = FALSE; if (!strcmp( curtype, "classic" )) { if (!gconv( GCONV_USER, 0 )) return 0; if (isNoPassAllowed( curuser )) { gconv( GCONV_PASS_ND, 0 ); if (!*curpass) { pnopass = TRUE; sprintf( psrvb, "%.31s-np", PAMService ); psrv = psrvb; } else psrv = PAMService; } else psrv = PAMService; pdata.usecur = TRUE; } else { sprintf( psrvb, "%.31s-%.31s", PAMService, curtype ); psrv = psrvb; pdata.usecur = FALSE; } pdata.gconv = gconv; if (!doPAMAuth( psrv, &pdata )) return 0; #elif defined(_AIX) if ((td->displayType & d_location) == dForeign) { char *tmpch; strncpy( hostname, td->name, sizeof(hostname) - 1 ); hostname[sizeof(hostname)-1] = '\0'; if ((tmpch = strchr( hostname, ':' ))) *tmpch = '\0'; } else hostname[0] = '\0'; /* tty names should only be 15 characters long */ # if 0 for (i = 0; i < 15 && td->name[i]; i++) { if (td->name[i] == ':' || td->name[i] == '.') tty[i] = '_'; else tty[i] = td->name[i]; } tty[i] = '\0'; # else memcpy( tty, "/dev/xdm/", 9 ); for (i = 0; i < 6 && td->name[i]; i++) { if (td->name[i] == ':' || td->name[i] == '.') tty[9 + i] = '_'; else tty[9 + i] = td->name[i]; } tty[9 + i] = '\0'; # endif if (!strcmp( curtype, "classic" )) { if (!gconv( GCONV_USER, 0 )) return 0; if (isNoPassAllowed( curuser )) { gconv( GCONV_PASS_ND, 0 ); if (!*curpass) { debug( "accepting despite empty password\n" ); goto done; } } else if (!gconv( GCONV_PASS, 0 )) return 0; enduserdb(); msg = NULL; if ((i = authenticate( curuser, curpass, &reenter, &msg ))) { debug( "authenticate() failed: %s\n", msg ); if (msg) free( msg ); loginfailed( curuser, hostname, tty ); if (i == ENOENT || i == ESAD) V_RET_AUTH; else V_RET_FAIL( 0 ); } if (reenter) { logError( "authenticate() requests more data: %s\n", msg ); free( msg ); V_RET_FAIL( 0 ); } } else if (!strcmp( curtype, "generic" )) { if (!gconv( GCONV_USER, 0 )) return 0; for (curret = 0;;) { msg = NULL; if ((i = authenticate( curuser, curret, &reenter, &msg ))) { debug( "authenticate() failed: %s\n", msg ); if (msg) free( msg ); loginfailed( curuser, hostname, tty ); if (i == ENOENT || i == ESAD) V_RET_AUTH; else V_RET_FAIL( 0 ); } if (curret) free( curret ); if (!reenter) break; if (!(curret = gconv( GCONV_HIDDEN, msg ))) return 0; free( msg ); } } else { logError( "Unsupported authentication type %\"s requested\n", curtype ); V_RET_FAIL( 0 ); } if (msg) { displayStr( V_MSG_INFO, msg ); free( msg ); } done: #else if (strcmp( curtype, "classic" )) { logError( "Unsupported authentication type %\"s requested\n", curtype ); V_RET_FAIL( 0 ); } if (!gconv( GCONV_USER, 0 )) return 0; if (!(p = getpwnam( curuser ))) { debug( "getpwnam() failed.\n" ); gconv( GCONV_PASS, 0 ); V_RET_AUTH; } if (p->pw_passwd[0] == '!' || p->pw_passwd[0] == '*') { debug( "account is locked\n" ); gconv( GCONV_PASS, 0 ); V_RET_AUTH; } # ifdef USESHADOW if ((sp = getspnam( curuser ))) { p->pw_passwd = sp->sp_pwdp; if (p->pw_passwd[0] == '!' || p->pw_passwd[0] == '*') { debug( "account is locked\n" ); gconv( GCONV_PASS, 0 ); V_RET_AUTH; } } else debug( "getspnam() failed: %m. Are you root?\n" ); # endif if (!*p->pw_passwd) { if (!td->allowNullPasswd) { debug( "denying user with empty password\n" ); gconv( GCONV_PASS, 0 ); V_RET_AUTH; } goto nplogin; } if (isNoPassAllowed( curuser, p )) { nplogin: gconv( GCONV_PASS_ND, 0 ); if (!*curpass) { debug( "accepting password-less login\n" ); goto done; } } else if (!gconv( GCONV_PASS, 0 )) return 0; # ifdef KERBEROS if (p->pw_uid) { int ret; char realm[REALM_SZ]; if (krb_get_lrealm( realm, 1 )) { logError( "Cannot get KerberosIV realm.\n" ); V_RET_FAIL( 0 ); } sprintf( krbtkfile, "%s.%.*s", TKT_ROOT, MAXPATHLEN - strlen( TKT_ROOT ) - 2, td->name ); krb_set_tkt_string( krbtkfile ); unlink( krbtkfile ); ret = krb_verify_user( curuser, "", realm, curpass, 1, "rcmd" ); if (ret == KSUCCESS) { chown( krbtkfile, p->pw_uid, p->pw_gid ); debug( "KerberosIV verify succeeded\n" ); goto done; } else if (ret != KDC_PR_UNKNOWN && ret != SKDC_CANT) { logError( "KerberosIV verification failure %\"s for %s\n", krb_get_err_text( ret ), curuser ); krbtkfile[0] = '\0'; V_RET_FAIL( 0 ); } debug( "KerberosIV verify failed: %s\n", krb_get_err_text( ret ) ); } krbtkfile[0] = '\0'; # endif /* KERBEROS */ # if defined(ultrix) || defined(__ultrix__) if (authenticate_user( p, curpass, NULL ) < 0) # elif defined(HAVE_PW_ENCRYPT) if (strcmp( pw_encrypt( curpass, p->pw_passwd ), p->pw_passwd )) # elif defined(HAVE_CRYPT) if (strcmp( crypt( curpass, p->pw_passwd ), p->pw_passwd )) # else if (strcmp( curpass, p->pw_passwd )) # endif { debug( "password verify failed\n" ); V_RET_AUTH; } done: #endif /* !defined(USE_PAM) && !defined(_AIX) */ debug( "restrict %s ...\n", curuser ); #if defined(USE_PAM) || defined(_AIX) if (!(p = getpwnam( curuser ))) { logError( "getpwnam(%s) failed.\n", curuser ); V_RET_FAIL( 0 ); } #endif if (!p->pw_uid) { if (!rootok && !td->allowRootLogin) V_RET_FAIL( "Root logins are not allowed" ); return 1; /* don't deny root to log in */ } #ifdef USE_PAM debug( " pam_acct_mgmt() ...\n" ); pretc = pam_acct_mgmt( pamh, 0 ); reInitErrorLog(); debug( " pam_acct_mgmt() returned: %s\n", pam_strerror( pamh, pretc ) ); if (pretc == PAM_NEW_AUTHTOK_REQD) { pdata.usecur = FALSE; pdata.gconv = conv_interact; /* pam will have output a message already, so no prepareErrorGreet() */ if (gconv != conv_interact || pnopass) { pam_end( pamh, PAM_SUCCESS ); pamh = 0; gSendInt( V_CHTOK_AUTH ); /* this cannot auth the wrong user, as only classic auths get here */ while (!doPAMAuth( PAMService, &pdata )) if (pdata.abort) return 0; gSendInt( V_PRE_OK ); } else gSendInt( V_CHTOK ); for (;;) { debug( " pam_chauthtok() ...\n" ); pretc = pam_chauthtok( pamh, PAM_CHANGE_EXPIRED_AUTHTOK ); reInitErrorLog(); debug( " pam_chauthtok() returned: %s\n", pam_strerror( pamh, pretc ) ); if (pdata.abort) { pam_end( pamh, PAM_SUCCESS ); pamh = 0; return 0; } if (pretc == PAM_SUCCESS) break; /* effectively there is only PAM_AUTHTOK_ERR */ gSendInt( V_FAIL ); } if (curpass) free( curpass ); curpass = newpass; newpass = 0; } else if (pretc != PAM_SUCCESS) { pam_end( pamh, pretc ); pamh = 0; V_RET_AUTH; } #elif defined(_AIX) /* USE_PAM */ msg = NULL; if (loginrestrictions( curuser, ((td->displayType & d_location) == dForeign) ? S_RLOGIN : S_LOGIN, tty, &msg ) == -1) { debug( "loginrestrictions() - %s\n", msg ? msg : "error" ); loginfailed( curuser, hostname, tty ); prepareErrorGreet(); if (msg) { displayStr( V_MSG_ERR, msg ); free( msg ); } gSendInt( V_AUTH ); return 0; } if (msg) free( (void *)msg ); #endif /* USE_PAM || _AIX */ #ifndef _AIX # ifdef HAVE_SETUSERCONTEXT # ifdef HAVE_LOGIN_GETCLASS lc = login_getclass( p->pw_class ); # else lc = login_getpwclass( p ); # endif if (!lc) V_RET_FAIL( 0 ); p->pw_shell = login_getcapstr( lc, "shell", p->pw_shell, p->pw_shell ); # endif # ifndef USE_PAM /* restrict_expired */ # if defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || defined(USESHADOW) # if !defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || (!defined(HAVE_SETUSERCONTEXT) && defined(USESHADOW)) if (sp) # endif { # define DEFAULT_WARN (2L * 7L) /* Two weeks */ tim = time( NULL ) / 86400L; # ifdef HAVE_SETUSERCONTEXT quietlog = login_getcapbool( lc, "hushlogin", 0 ); warntime = login_getcaptime( lc, "warnexpire", DEFAULT_WARN * 86400L, DEFAULT_WARN * 86400L ) / 86400L; # else quietlog = 0; # ifdef USESHADOW warntime = sp->sp_warn != -1 ? sp->sp_warn : DEFAULT_WARN; # else warntime = DEFAULT_WARN; # endif # endif # ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE if (p->pw_expire) { expir = p->pw_expire / 86400L; # else if (sp->sp_expire != -1) { expir = sp->sp_expire; # endif if (tim > expir) { displayStr( V_MSG_ERR, "Your account has expired;" " please contact your system administrator" ); gSendInt( V_FAIL ); LC_RET0; } else if (tim > (expir - warntime) && !quietlog) { displayMsg( V_MSG_INFO, "Warning: your account will expire in %d day(s)", expir - tim ); } } # ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE if (p->pw_change) { expir = p->pw_change / 86400L; # else if (!sp->sp_lstchg) { displayStr( V_MSG_ERR, "You are required to change your password immediately" " (root enforced)" ); /* XXX todo password change */ gSendInt( V_FAIL ); LC_RET0; } else if (sp->sp_max != -1) { expir = sp->sp_lstchg + sp->sp_max; if (sp->sp_inact != -1 && tim > expir + sp->sp_inact) { displayStr( V_MSG_ERR, "Your account has expired;" " please contact your system administrator" ); gSendInt( V_FAIL ); LC_RET0; } # endif if (tim > expir) { displayStr( V_MSG_ERR, "You are required to change your password immediately" " (password aged)" ); /* XXX todo password change */ gSendInt( V_FAIL ); LC_RET0; } else if (tim > (expir - warntime) && !quietlog) { displayMsg( V_MSG_INFO, "Warning: your password will expire in %d day(s)", expir - tim ); } } } # endif /* HAVE_STRUCT_PASSWD_PW_EXPIRE || USESHADOW */ /* restrict_nologin */ # ifndef _PATH_NOLOGIN # define _PATH_NOLOGIN "/etc/nologin" # endif if (( # ifdef HAVE_SETUSERCONTEXT /* Do we ignore a nologin file? */ !login_getcapbool( lc, "ignorenologin", 0 )) && (!stat( (nolg = login_getcapstr( lc, "nologin", "", NULL )), &st ) || # endif !stat( (nolg = _PATH_NOLOGIN), &st ))) { if (st.st_size && (fd = open( nolg, O_RDONLY )) >= 0) { if ((buf = Malloc( st.st_size + 1 ))) { if (read( fd, buf, st.st_size ) == st.st_size) { close( fd ); buf[st.st_size] = 0; displayStr( V_MSG_ERR, buf ); free( buf ); gSendInt( V_FAIL ); LC_RET0; } free( buf ); } close( fd ); } displayStr( V_MSG_ERR, "Logins are not allowed at the moment.\nTry again later" ); gSendInt( V_FAIL ); LC_RET0; } /* restrict_time */ # if defined(HAVE_SETUSERCONTEXT) && defined(HAVE_AUTH_TIMEOK) if (!auth_timeok( lc, time( NULL ) )) { displayStr( V_MSG_ERR, "You are not allowed to login at the moment" ); gSendInt( V_FAIL ); LC_RET0; } # endif # ifdef HAVE_GETUSERSHELL for (;;) { if (!(s = getusershell())) { debug( "shell not in /etc/shells\n" ); endusershell(); V_RET_FAIL( "Your login shell is not listed in /etc/shells" ); } if (!strcmp( s, p->pw_shell )) { endusershell(); break; } } # endif # endif /* !USE_PAM */ /* restrict_nohome */ # ifdef HAVE_SETUSERCONTEXT if (login_getcapbool( lc, "requirehome", 0 )) { struct stat st; if (!*p->pw_dir || stat( p->pw_dir, &st ) || st.st_uid != p->pw_uid) { displayStr( V_MSG_ERR, "Home folder not available" ); gSendInt( V_FAIL ); LC_RET0; } } # endif #endif /* !_AIX */ return 1; } static const char *envvars[] = { "TZ", /* SYSV and SVR4, but never hurts */ #ifdef _AIX "AUTHSTATE", /* for kerberos */ #endif NULL }; #if defined(USE_PAM) && defined(HAVE_INITGROUPS) static int num_saved_gids; static gid_t *saved_gids; static int saveGids( void ) { num_saved_gids = getgroups( 0, 0 ); if (!(saved_gids = Malloc( sizeof(gid_t) * num_saved_gids ))) return 0; if (getgroups( num_saved_gids, saved_gids ) < 0) { logError( "saving groups failed: %m\n" ); return 0; } return 1; } static int restoreGids( void ) { if (setgroups( num_saved_gids, saved_gids ) < 0) { logError( "restoring groups failed: %m\n" ); return 0; } if (setgid( p->pw_gid ) < 0) { logError( "restoring gid failed: %m\n" ); return 0; } return 1; } #endif /* USE_PAM && HAVE_INITGROUPS */ static int resetGids( void ) { #ifdef HAVE_INITGROUPS if (setgroups( 0, &p->pw_gid /* anything */ ) < 0) { logError( "restoring groups failed: %m\n" ); return 0; } #endif if (setgid( 0 ) < 0) { logError( "restoring gid failed: %m\n" ); return 0; } return 1; } static int setGid( const char *name, int gid ) { if (setgid( gid ) < 0) { logError( "setgid(%d) (user %s) failed: %m\n", gid, name ); return 0; } #ifdef HAVE_INITGROUPS if (initgroups( name, gid ) < 0) { logError( "initgroups for %s failed: %m\n", name ); setgid( 0 ); return 0; } #endif /* QNX4 doesn't support multi-groups, no initgroups() */ return 1; } static int setUid( const char *name, int uid ) { if (setuid( uid ) < 0) { logError( "setuid(%d) (user %s) failed: %m\n", uid, name ); return 0; } return 1; } static int setUser( const char *name, int uid, int gid ) { if (setGid( name, gid )) { if (setUid( name, uid )) return 1; resetGids(); } return 0; } #if defined(SECURE_RPC) || defined(K5AUTH) static void nukeAuth( int len, const char *name ) { int i; for (i = 0; i < td->authNum; i++) if (td->authorizations[i]->name_length == len && !memcmp( td->authorizations[i]->name, name, len )) { memcpy( &td->authorizations[i], &td->authorizations[i+1], sizeof(td->authorizations[i]) * (--td->authNum - i) ); break; } } #endif static void mergeSessionArgs( int cansave ) { char *mfname; const char *fname; int i, needsave; mfname = 0; fname = ".dmrc"; if ((!curdmrc || newdmrc) && *dmrcDir) if (strApp( &mfname, dmrcDir, "/", curuser, fname, (char *)0 )) fname = mfname; needsave = 0; if (!curdmrc) { curdmrc = iniLoad( fname ); if (!curdmrc) { strDup( &curdmrc, "[Desktop]\nSession=default\n" ); needsave = 1; } } if (newdmrc) { curdmrc = iniMerge( curdmrc, newdmrc ); needsave = 1; } if (needsave && cansave) if (!iniSave( curdmrc, fname ) && errno == ENOENT && mfname) { for (i = 0; mfname[i]; i++) if (mfname[i] == '/') { mfname[i] = 0; mkdir( mfname, 0755 ); mfname[i] = '/'; } iniSave( curdmrc, mfname ); } if (mfname) free( mfname ); } static int createClientLog( const char *log ) { char randstr[32], *randstrp = 0, *lname; int lfd; for (;;) { struct expando macros[] = { { 'd', 0, td->name }, { 'u', 0, curuser }, { 'r', 0, randstrp }, { 0, 0, 0 } }; if (!(lname = expandMacros( log, macros ))) exit( 1 ); unlink( lname ); if ((lfd = open( lname, O_WRONLY|O_CREAT|O_EXCL, 0600 )) >= 0) { dup2( lfd, 1 ); dup2( lfd, 2 ); close( lfd ); free( lname ); return TRUE; } if (errno != EEXIST || !macros[2].uses) { free( lname ); return FALSE; } logInfo( "Session log file %s not usable, trying another one.\n", lname ); free( lname ); sprintf( randstr, "%d", secureRandom() ); randstrp = randstr; } }
/* * passwd - change a user's password file information * * This command controls the password file and commands which are used * to modify it. * * The valid options are * * -d delete the password for the named account (*) * -e expire the password for the named account (*) * -f execute chfn command to interpret flags * -g execute gpasswd command to interpret flags * -i # set sp_inact to # days (*) * -k change password only if expired * -l lock the password of the named account (*) * -n # set sp_min to # days (*) * -r # change password in # repository * -s execute chsh command to interpret flags * -S show password status of named account * -u unlock the password of the named account (*) * -w # set sp_warn to # days (*) * -x # set sp_max to # days (*) * * (*) requires root permission to execute. * * All of the time fields are entered in days and converted to the * appropriate internal format. For finer resolute the chage * command must be used. */ int main (int argc, char **argv) { const struct passwd *pw; /* Password file entry for user */ #ifndef USE_PAM char *cp; /* Miscellaneous character pointing */ const struct spwd *sp; /* Shadow file entry for user */ #endif /* !USE_PAM */ (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); /* * The program behaves differently when executed by root than when * executed by a normal user. */ amroot = (getuid () == 0); /* * Get the program name. The program name is used as a prefix to * most error messages. */ Prog = Basename (argv[0]); sanitize_env (); OPENLOG ("passwd"); { /* * Parse the command line options. */ int option_index = 0; int c; static struct option long_options[] = { {"all", no_argument, NULL, 'a'}, {"delete", no_argument, NULL, 'd'}, {"expire", no_argument, NULL, 'e'}, {"help", no_argument, NULL, 'h'}, {"inactive", required_argument, NULL, 'i'}, {"keep-tokens", no_argument, NULL, 'k'}, {"lock", no_argument, NULL, 'l'}, {"mindays", required_argument, NULL, 'n'}, {"quiet", no_argument, NULL, 'q'}, {"root", required_argument, NULL, 'R'}, {"repository", required_argument, NULL, 'r'}, {"status", no_argument, NULL, 'S'}, {"unlock", no_argument, NULL, 'u'}, {"warndays", required_argument, NULL, 'w'}, {"maxdays", required_argument, NULL, 'x'}, {NULL, 0, NULL, '\0'} }; while ((c = getopt_long (argc, argv, "adei:kln:qR:r:Suw:x:", long_options, &option_index)) != -1) { switch (c) { case 'a': aflg = true; break; case 'd': dflg = true; anyflag = true; break; case 'e': eflg = true; anyflag = true; break; case 'i': if ( (getlong (optarg, &inact) == 0) || (inact < -1)) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, optarg); usage (E_BAD_ARG); } iflg = true; anyflag = true; break; case 'k': /* change only if expired, like Linux-PAM passwd -k. */ kflg = true; /* ok for users */ break; case 'l': lflg = true; anyflag = true; break; case 'n': if ( (getlong (optarg, &age_min) == 0) || (age_min < -1)) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, optarg); usage (E_BAD_ARG); } nflg = true; anyflag = true; break; case 'q': qflg = true; /* ok for users */ break; case 'R': if ('/' != optarg[0]) { fprintf (stderr, _("%s: invalid chroot path '%s'\n"), Prog, optarg); exit (E_BAD_ARG); } newroot = optarg; if (access (newroot, F_OK) != 0) { fprintf(stderr, _("%s: chroot directory %s does not exist\n"), Prog, newroot); exit (E_BAD_ARG); } if ( chroot(newroot) != 0 ) { fprintf(stderr, _("%s: unable to chroot to directory %s\n"), Prog, newroot); exit (E_BAD_ARG); } break; case 'r': /* -r repository (files|nis|nisplus) */ /* only "files" supported for now */ if (strcmp (optarg, "files") != 0) { fprintf (stderr, _("%s: repository %s not supported\n"), Prog, optarg); exit (E_BAD_ARG); } break; case 'S': Sflg = true; /* ok for users */ break; case 'u': uflg = true; anyflag = true; break; case 'w': if ( (getlong (optarg, &warn) == 0) || (warn < -1)) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, optarg); usage (E_BAD_ARG); } wflg = true; anyflag = true; break; case 'x': if ( (getlong (optarg, &age_max) == 0) || (age_max < -1)) { fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog, optarg); usage (E_BAD_ARG); } xflg = true; anyflag = true; break; default: usage (E_BAD_ARG); } } } /* * Now I have to get the user name. The name will be gotten from the * command line if possible. Otherwise it is figured out from the * environment. */ pw = get_my_pwent (); if (NULL == pw) { fprintf (stderr, _("%s: Cannot determine your user name.\n"), Prog); SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)", (unsigned long) getuid ())); exit (E_NOPERM); } myname = xstrdup (pw->pw_name); if (optind < argc) { name = argv[optind]; } else { name = myname; } /* * Make sure that at most one username was specified. */ if (argc > (optind+1)) { usage (E_USAGE); } /* * The -a flag requires -S, no other flags, no username, and * you must be root. --marekm */ if (aflg) { if (anyflag || !Sflg || (optind < argc)) { usage (E_USAGE); } if (!amroot) { fprintf (stderr, _("%s: Permission denied.\n"), Prog); exit (E_NOPERM); } setpwent (); while ( (pw = getpwent ()) != NULL ) { print_status (pw); } endpwent (); exit (E_SUCCESS); } #if 0 /* * Allow certain users (administrators) to change passwords of * certain users. Not implemented yet. --marekm */ if (may_change_passwd (myname, name)) amroot = 1; #endif /* * If any of the flags were given, a user name must be supplied on * the command line. Only an unadorned command line doesn't require * the user's name be given. Also, -x, -n, -w, -i, -e, -d, * -l, -u may appear with each other. -S, -k must appear alone. */ /* * -S now ok for normal users (check status of my own account), and * doesn't require username. --marekm */ if (anyflag && optind >= argc) { usage (E_USAGE); } if ( (Sflg && kflg) || (anyflag && (Sflg || kflg))) { usage (E_USAGE); } if (anyflag && !amroot) { fprintf (stderr, _("%s: Permission denied.\n"), Prog); exit (E_NOPERM); } pw = xgetpwnam (name); if (NULL == pw) { fprintf (stderr, _("%s: user '%s' does not exist\n"), Prog, name); exit (E_NOPERM); } #ifdef WITH_SELINUX /* only do this check when getuid()==0 because it's a pre-condition for changing a password without entering the old one */ if ((is_selinux_enabled() > 0) && (getuid() == 0) && (check_selinux_access (name, pw->pw_uid, PASSWD__PASSWD) != 0)) { security_context_t user_context = NULL; const char *user = "******"; if (getprevcon (&user_context) == 0) { user = user_context; } SYSLOG ((LOG_ALERT, "%s is not authorized to change the password of %s", user, name)); fprintf(stderr, _("%s: %s is not authorized to change the password of %s\n"), Prog, user, name); if (NULL != user_context) { freecon (user_context); } exit (E_NOPERM); } #endif /* WITH_SELINUX */ /* * If the UID of the user does not match the current real UID, * check if I'm root. */ if (!amroot && (pw->pw_uid != getuid ())) { fprintf (stderr, _("%s: You may not view or modify password information for %s.\n"), Prog, name); SYSLOG ((LOG_WARN, "%s: can't view or modify password information for %s", Prog, name)); closelog (); exit (E_NOPERM); } if (Sflg) { print_status (pw); exit (E_SUCCESS); } #ifndef USE_PAM /* * The user name is valid, so let's get the shadow file entry. */ sp = getspnam (name); /* !USE_PAM, no need for xgetspnam */ if (NULL == sp) { sp = pwd_to_spwd (pw); } cp = sp->sp_pwdp; /* * If there are no other flags, just change the password. */ if (!anyflag) { STRFCPY (crypt_passwd, cp); /* * See if the user is permitted to change the password. * Otherwise, go ahead and set a new password. */ check_password (pw, sp); /* * Let the user know whose password is being changed. */ if (!qflg) { printf (_("Changing password for %s\n"), name); } if (new_password (pw)) { fprintf (stderr, _("The password for %s is unchanged.\n"), name); closelog (); exit (E_NOPERM); } do_update_pwd = true; do_update_age = true; } #endif /* !USE_PAM */ /* * Before going any further, raise the ulimit to prevent colliding * into a lowered ulimit, and set the real UID to root to protect * against unexpected signals. Any keyboard signals are set to be * ignored. */ pwd_init (); #ifdef USE_PAM /* * Don't set the real UID for PAM... */ if (!anyflag) { do_pam_passwd (name, qflg, kflg); exit (E_SUCCESS); } #endif /* USE_PAM */ if (setuid (0) != 0) { fputs (_("Cannot change ID to root.\n"), stderr); SYSLOG ((LOG_ERR, "can't setuid(0)")); closelog (); exit (E_NOPERM); } if (spw_file_present ()) { update_shadow (); } else { update_noshadow (); } nscd_flush_cache ("passwd"); nscd_flush_cache ("group"); SYSLOG ((LOG_INFO, "password for '%s' changed by '%s'", name, myname)); closelog (); if (!qflg) { if (!anyflag) { #ifndef USE_PAM printf (_("%s: password changed.\n"), Prog); #endif /* USE_PAM */ } else { printf (_("%s: password expiry information changed.\n"), Prog); } } return E_SUCCESS; }
/* * expiry - check and enforce password expiration policy * * expiry checks (-c) the current password expiration and forces (-f) * changes when required. It is callable as a normal user command. */ int main (int argc, char **argv) { struct passwd *pwd; struct spwd *spwd; Prog = Basename (argv[0]); sanitize_env (); /* * Start by disabling all of the keyboard signals. */ (void) signal (SIGHUP, catch_signals); (void) signal (SIGINT, catch_signals); (void) signal (SIGQUIT, catch_signals); #ifdef SIGTSTP (void) signal (SIGTSTP, catch_signals); #endif /* * expiry takes one of two arguments. The default action is to give * the usage message. */ (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); OPENLOG ("expiry"); process_flags (argc, argv); /* * Get user entries for /etc/passwd and /etc/shadow */ pwd = get_my_pwent (); if (NULL == pwd) { fprintf (stderr, _("%s: Cannot determine your user name.\n"), Prog); SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)", (unsigned long) getuid ())); exit (10); } spwd = getspnam (pwd->pw_name); /* !USE_PAM, No need for xgetspnam */ /* * If checking accounts, use agecheck() function. */ if (cflg) { /* * Print out number of days until expiration. */ agecheck (spwd); /* * Exit with status indicating state of account. */ exit (isexpired (pwd, spwd)); } /* * Otherwise, force a password change with the expire() function. * It will force the change or give a message indicating what to * do. * It won't return unless the account is unexpired. */ (void) expire (pwd, spwd); return E_SUCCESS; }
void Pass(char *param) { struct passwd *pw; struct spwd *spw; char *passwd, salt[13]; if (!input_user) { outs("503 Login with USER first."); return; }; /* judge and chdir to its home directory */ if (!anonymous_login) { if (system_uid != 0) { outs("530 Login incorrect."); input_user = 0; return; }; if ((pw = getpwnam(username)) == NULL) { outs("530 Login incorrect."); input_user = 0; return; }; passwd = pw->pw_passwd; if (passwd == NULL || strcmp(passwd, "x") == 0) { spw = getspnam(username); if (spw == NULL || (passwd = spw->sp_pwdp) == NULL) { outs("530 Login incorrect."); input_user = 0; return; }; }; strncpy(salt, passwd, 12); if (strcmp(passwd, crypt((const char*)param, (const char*)salt)) != 0) { outs("530 Login incorrect."); input_user = 0; return; }; strcpy(path, ""); setuid(pw->pw_uid); if (pw->pw_dir) strncpy(path, pw->pw_dir, PATH_MAX); else strcpy(path, "/"); outs("230 User %s logged in.", username); chdir(path); getcwd(path, PATH_MAX); user_valid = 1; } else { if ((pw = getpwuid(system_uid)) == NULL) { outs("530 Login incorrect."); input_user = 0; return; }; if (pw->pw_dir) strncpy(basedir, pw->pw_dir, PATH_MAX); else strcpy(basedir, ""); strcpy(path, "/"); chdir(basedir); getcwd(basedir, PATH_MAX); user_valid = 1; outs("230 Anonymous access granted, restrictions apply."); }; user_valid = 1; outs("230 Anonymous access granted, restrictions apply."); };
int main(int argc, char **argv){ XEvent ev; KeySym ks; char cbuf[10], rbuf[128]; /* shadow appears to suggest 127 a good value here */ int clen, rlen=0; long goodwill= INITIALGOODWILL, timeout= 0; XSetWindowAttributes attrib; Cursor cursor; Pixmap csr_source,csr_mask; XColor csr_fg, csr_bg, dummy, black; int ret, screen, blank = 0, fork_after = 0; #ifdef SHADOW_PWD struct spwd *sp; #endif struct timeval tv; int tvt, gs; int opt, index, cmdlen = 0; char cmdstr[CMDMAXLEN] = {0}; #if 0 while (argc > 1) { if ((strcmp(argv[1], "-b") == 0)) { blank = 1; argc--; argv++; } else if ((strcmp(argv[1], "-f") == 0)) { fork_after = 1; argc--; argv++; } else { fprintf(stderr,"xtrlock (version %s); usage: xtrlock [-b] [-f]\n", program_version); exit(1); } } #endif while ((opt = getopt (argc, argv, "bc:f")) != -1) { switch (opt) { case 'b': blank = 1; break; case 'c': strncpy(cmdstr, optarg, CMDMAXLEN - 1); cmdlen = strlen(cmdstr); break; case 'f': fork_after = 1; break; default: fprintf(stderr,"xtrlock (version %s mod); usage: xtrlock [-b] [-c command] [-f]\n", program_version); exit(1); } } /* Make sure not to consume the next input option */ if (cmdstr[0] == '-') { fprintf (stderr, "Option -c requires an argument.\n"); exit(1); } if (cmdstr[0]) { for (index = optind; index < argc; index++) { cmdlen += strlen(argv[index]) + 1; if (cmdlen < CMDMAXLEN) { strcat(cmdstr, " "); strcat(cmdstr, argv[index]); } else { fprintf (stderr, "Command too large. Ignoring.\n"); cmdlen = 0; break; } } } if (cmdlen) fprintf(stdout, "cmd: [%s]\n", cmdstr); errno=0; pw= getpwuid(getuid()); if (!pw) { perror("password entry for uid not found"); exit(1); } #ifdef SHADOW_PWD sp = getspnam(pw->pw_name); if (sp) pw->pw_passwd = sp->sp_pwdp; endspent(); #endif /* logically, if we need to do the following then the same applies to being installed setgid shadow. we do this first, because of a bug in linux. --jdamery */ if (setgid(getgid())) { perror("setgid"); exit(1); } /* we can be installed setuid root to support shadow passwords, and we don't need root privileges any longer. --marekm */ if (setuid(getuid())) { perror("setuid"); exit(1); } if (strlen(pw->pw_passwd) < 13) { fputs("password entry has no pwd\n",stderr); exit(1); } display= XOpenDisplay(0); if (display==NULL) { fprintf(stderr,"xtrlock (version %s): cannot open display\n", program_version); exit(1); } attrib.override_redirect= True; if (blank) { screen = DefaultScreen(display); attrib.background_pixel = BlackPixel(display, screen); window= XCreateWindow(display,DefaultRootWindow(display), 0,0,DisplayWidth(display, screen),DisplayHeight(display, screen), 0,DefaultDepth(display, screen), CopyFromParent, DefaultVisual(display, screen), CWOverrideRedirect|CWBackPixel,&attrib); XAllocNamedColor(display, DefaultColormap(display, screen), "black", &black, &dummy); } else { window= XCreateWindow(display,DefaultRootWindow(display), 0,0,1,1,0,CopyFromParent,InputOnly,CopyFromParent, CWOverrideRedirect,&attrib); } XSelectInput(display,window,KeyPressMask|KeyReleaseMask); csr_source= XCreateBitmapFromData(display,window,lock_bits,lock_width,lock_height); csr_mask= XCreateBitmapFromData(display,window,mask_bits,mask_width,mask_height); ret = XAllocNamedColor(display, DefaultColormap(display, DefaultScreen(display)), "steelblue3", &dummy, &csr_bg); if (ret==0) XAllocNamedColor(display, DefaultColormap(display, DefaultScreen(display)), "black", &dummy, &csr_bg); ret = XAllocNamedColor(display, DefaultColormap(display,DefaultScreen(display)), "grey25", &dummy, &csr_fg); if (ret==0) XAllocNamedColor(display, DefaultColormap(display, DefaultScreen(display)), "white", &dummy, &csr_bg); cursor= XCreatePixmapCursor(display,csr_source,csr_mask,&csr_fg,&csr_bg, lock_x_hot,lock_y_hot); XMapWindow(display,window); /*Sometimes the WM doesn't ungrab the keyboard quickly enough if *launching xtrlock from a keystroke shortcut, meaning xtrlock fails *to start We deal with this by waiting (up to 100 times) for 10,000 *microsecs and trying to grab each time. If we still fail *(i.e. after 1s in total), then give up, and emit an error */ gs=0; /*gs==grab successful*/ for (tvt=0 ; tvt<100; tvt++) { ret = XGrabKeyboard(display,window,False,GrabModeAsync,GrabModeAsync, CurrentTime); if (ret == GrabSuccess) { gs=1; break; } /*grab failed; wait .01s*/ tv.tv_sec=0; tv.tv_usec=10000; select(1,NULL,NULL,NULL,&tv); } if (gs==0){ fprintf(stderr,"xtrlock (version %s): cannot grab keyboard\n", program_version); exit(1); } if (XGrabPointer(display,window,False,(KeyPressMask|KeyReleaseMask)&0, GrabModeAsync,GrabModeAsync,None, cursor,CurrentTime)!=GrabSuccess) { XUngrabKeyboard(display,CurrentTime); fprintf(stderr,"xtrlock (version %s): cannot grab pointer\n", program_version); exit(1); } if (fork_after) { pid_t pid = fork(); if (pid < 0) { fprintf(stderr,"xtrlock (version %s): cannot fork: %s\n", program_version, strerror(errno)); exit(1); } else if (pid > 0) { exit(0); } } for (;;) { XNextEvent(display,&ev); switch (ev.type) { case KeyPress: if (ev.xkey.time < timeout) { XBell(display,0); break; } clen= XLookupString(&ev.xkey,cbuf,9,&ks,0); switch (ks) { case XK_Escape: case XK_Clear: rlen=0; break; case XK_Delete: case XK_BackSpace: if (rlen>0) rlen--; break; case XK_Linefeed: case XK_Return: if (rlen==0) break; rbuf[rlen]=0; if (passwordok(rbuf)) goto loop_x; XBell(display,0); rlen= 0; if (timeout) { goodwill+= ev.xkey.time - timeout; if (goodwill > MAXGOODWILL) { goodwill= MAXGOODWILL; } } timeout= -goodwill*GOODWILLPORTION; goodwill+= timeout; timeout+= ev.xkey.time + TIMEOUTPERATTEMPT; break; default: if (clen != 1) break; /* allow space for the trailing \0 */ if (rlen < (sizeof(rbuf) - 1)){ rbuf[rlen]=cbuf[0]; rlen++; } break; } break; default: break; } } loop_x: if (cmdlen) execl("/bin/sh", "sh", "-c", cmdstr, (char *) 0); exit(0); }
int main(int argc, char *argv[]) { char *username, *password, *encrypted, *p; struct passwd *pwd; struct spwd *spwd; Boolean authOk; size_t len; long lnmax; /* Determine size of buffer required for a username, and allocate it */ lnmax = sysconf(_SC_LOGIN_NAME_MAX); if (lnmax == -1) /* If limit is indeterminate */ lnmax = 256; /* make a guess */ username = malloc(lnmax); if (username == NULL) errExit("malloc"); printf("Username: "******"couldn't get password record"); spwd = getspnam(username); if (spwd == NULL && errno == EACCES) fatal("no permission to read shadow password file"); if (spwd != NULL) /* If there is a shadow password record */ pwd->pw_passwd = spwd->sp_pwdp; /* Use the shadow password */ password = getpass("Password: "******"crypt"); authOk = strcmp(encrypted, pwd->pw_passwd) == 0; if (!authOk) { printf("Incorrect password\n"); exit(EXIT_FAILURE); } printf("Successfully authenticated: UID=%ld\n", (long) pwd->pw_uid); /* Now do authenticated work... */ exit(EXIT_SUCCESS); }
int main(int argc, char **argv) { int sniff_fd; uid_t uid; struct stat sniff_stat; struct termios term; struct spwd *spasswd; char *password; char *hash, *hash_attempt; char *salt; salt = malloc(sizeof(char) * MAX_SALT_LEN); password = malloc(sizeof(char) * MAX_PASSWD_LEN); /** Check that the student is running the program by comparing the real UID ** of the process with that of the student. (Assume you are the student for ** this testing.) If the test fails, print an error message and exit. */ uid = getuid(); if (STUDENT_UID != uid && 0 != uid) { fprintf(stderr, "error: incorrect user id\n"); return EXIT_FAILURE; } /** Prompt the user for his or her password, and validate it against the one ** stored in the password file. If the password is incorrect, print an error ** message and exit. */ /* Retrieve hash and salt for student account from shadow file */ if (0 == (spasswd = getspnam(STUDENT_NAME))) { fprintf(stderr, "error: could not retrieve hash from shadow\n"); return EXIT_FAILURE; } hash = spasswd->sp_pwdp; strncpy(salt, hash, (int)(strrchr(hash, '$') + 1 - hash)); if (0 != tcgetattr(STDIN_FILENO, &term)) { perror("tcgetattr"); return EXIT_FAILURE; } /* Turn off terminal echo */ term.c_lflag &= ~ECHO; if (0 != tcsetattr(STDIN_FILENO, TCSADRAIN, &term)) { perror("tcsetattr"); return EXIT_FAILURE; } /* Get password, generate hash, then zero password memory */ printf("Password: "******"tcsetattr"); return EXIT_FAILURE; } putchar('\n'); /* Verify password hash */ if (strcmp(hash, hash_attempt)) { fprintf(stderr, "error: invalid password\n"); return EXIT_FAILURE; } /** If the current working directory does not contain a file called sniff, ** print an error message and exit. */ if (-1 == (sniff_fd = open("./sniff", O_RDONLY | O_NOFOLLOW))) { fprintf(stderr, "error: sniff executable not found\n"); return EXIT_FAILURE; } /** If the sniff is not owned by the student, or is not executable by the ** owner of the file, or can be read, written, or executed by anyone else ** (except, of course, root), print an error message and exit. */ if (-1 == fstat(sniff_fd, &sniff_stat)) { perror("fstat"); return EXIT_FAILURE; } /* Check if student owns sniff */ if (STUDENT_UID != sniff_stat.st_uid) { fprintf(stderr, "error: student is not owner of sniff\n"); return EXIT_FAILURE; } /* Check permissions */ if (!(sniff_stat.st_mode & 0100) || sniff_stat.st_mode & 0077) { fprintf(stderr, "error: sniff has invalid permissions\n"); return EXIT_FAILURE; } /** If sniff was created or modified over 1 minute ago, print an error ** message and exit. */ if (time(NULL) - sniff_stat.st_mtime > 60) { fprintf(stderr, "error: sniff was modified over one minute ago\n"); return EXIT_FAILURE; } /** Change the ownership of sniff to root (UID 0), its group to proj (GID ** 95), and its protection mode to 04550 (meaning setuid to owner, and only ** readable and executable by the owner and group members). */ chown("./sniff", SNIFF_OWNER, SNIFF_GROUP); chmod("./sniff", SNIFF_MODE); return EXIT_SUCCESS; }
int auth_change_pwd(char *user, char *newpwd) { struct passwd *spw; struct spwd *stp; char hash[35] = ""; long today; FILE *fd; if (0 != lckpwdf()) { return 1; } /* open passwd */ spw = getpwnam(user); if (spw == 0) { return 1; } if (g_strncmp(spw->pw_passwd, "x", 3) != 0) { /* old system with only passwd */ if (auth_crypt_pwd(spw->pw_passwd, newpwd, hash) != 0) { ulckpwdf(); return 1; } spw->pw_passwd = g_strdup(hash); fd = fopen("/etc/passwd", "rw"); putpwent(spw, fd); } else { /* the system is using shadow */ stp = getspnam(user); if (stp == 0) { return 1; } /* old system with only passwd */ if (auth_crypt_pwd(stp->sp_pwdp, newpwd, hash) != 0) { ulckpwdf(); return 1; } stp->sp_pwdp = g_strdup(hash); today = g_time1() / SECS_PER_DAY; stp->sp_lstchg = today; stp->sp_expire = today + stp->sp_max + stp->sp_inact; fd = fopen("/etc/shadow", "rw"); putspent(stp, fd); } ulckpwdf(); return 0; }
gchar * mdm_verify_user (MdmDisplay *d, const char *username, gboolean allow_retry) { gchar *login, *passwd, *ppasswd; struct passwd *pwent; struct spwd *sp; #if defined (HAVE_PASSWDEXPIRED) && defined (HAVE_CHPASS) \ || defined (HAVE_LOGINRESTRICTIONS) gchar *message = NULL; #endif #if defined (HAVE_PASSWDEXPIRED) && defined (HAVE_CHPASS) gchar *info_msg = NULL, *response = NULL; gint reEnter, ret; #endif if (d->attached && d->timed_login_ok) mdm_slave_greeter_ctl_no_ret (MDM_STARTTIMER, ""); if (username == NULL) { authenticate_again: /* Ask for the user's login */ mdm_verify_select_user (NULL); mdm_slave_greeter_ctl_no_ret (MDM_MSG, _("Please enter your username")); login = mdm_slave_greeter_ctl (MDM_PROMPT, _("Username:"******""); g_free (login); return NULL; } } mdm_slave_greeter_ctl_no_ret (MDM_MSG, ""); if (mdm_daemon_config_get_value_bool (MDM_KEY_DISPLAY_LAST_LOGIN)) { char *info = mdm_get_last_info (login); mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, info); g_free (info); } } else { login = g_strdup (username); } mdm_slave_greeter_ctl_no_ret (MDM_SETLOGIN, login); pwent = getpwnam (login); setspent (); /* Lookup shadow password */ sp = getspnam (login); /* Use shadow password when available */ if (sp != NULL) { ppasswd = g_strdup (sp->sp_pwdp); } else { /* In case shadow password cannot be retrieved (when using NIS authentication for example), use standard passwd */ if (pwent != NULL && pwent->pw_passwd != NULL) ppasswd = g_strdup (pwent->pw_passwd); else /* If no password can be retrieved, set it to NULL */ ppasswd = NULL; } endspent (); /* Request the user's password */ if (pwent != NULL && ve_string_empty (ppasswd)) { /* eeek a passwordless account */ passwd = g_strdup (""); } else { passwd = mdm_slave_greeter_ctl (MDM_NOECHO, _("Password:"******""); if (mdm_slave_greeter_check_interruption ()) { if (d->attached) mdm_slave_greeter_ctl_no_ret (MDM_STOPTIMER, ""); g_free (login); g_free (passwd); g_free (ppasswd); return NULL; } } if (d->attached) mdm_slave_greeter_ctl_no_ret (MDM_STOPTIMER, ""); if (pwent == NULL) { mdm_sleep_no_signal (mdm_daemon_config_get_value_int (MDM_KEY_RETRY_DELAY)); mdm_debug ("Couldn't authenticate user"); print_cant_auth_errbox (); g_free (login); g_free (passwd); g_free (ppasswd); return NULL; } /* Check whether password is valid */ if (ppasswd == NULL || (ppasswd[0] != '\0' && strcmp (crypt (passwd, ppasswd), ppasswd) != 0)) { mdm_sleep_no_signal (mdm_daemon_config_get_value_int (MDM_KEY_RETRY_DELAY)); mdm_debug ("Couldn't authenticate user"); print_cant_auth_errbox (); g_free (login); g_free (passwd); g_free (ppasswd); return NULL; } if (( ! mdm_daemon_config_get_value_bool (MDM_KEY_ALLOW_ROOT) || ( ! mdm_daemon_config_get_value_bool (MDM_KEY_ALLOW_REMOTE_ROOT) && ! d->attached)) && pwent->pw_uid == 0) { mdm_debug ("Root login disallowed on display '%s'", d->name); mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, _("The system administrator " "is not allowed to login " "from this screen")); /*mdm_slave_greeter_ctl_no_ret (MDM_ERRDLG, _("Root login disallowed"));*/ g_free (login); g_free (passwd); g_free (ppasswd); return NULL; } #ifdef HAVE_LOGINRESTRICTIONS /* Check with the 'loginrestrictions' function if the user has been disallowed */ if (loginrestrictions (login, 0, NULL, &message) != 0) { mdm_debug ("User not allowed to log in"); mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, _("\nThe system administrator " "has disabled your " "account.")); g_free (login); g_free (passwd); g_free (ppasswd); if (message != NULL) free (message); return NULL; } if (message != NULL) free (message); message = NULL; #else /* ! HAVE_LOGINRESTRICTIONS */ /* check for the standard method of disallowing users */ if (pwent->pw_shell != NULL && (strcmp (pwent->pw_shell, NOLOGIN) == 0 || strcmp (pwent->pw_shell, "/bin/true") == 0 || strcmp (pwent->pw_shell, "/bin/false") == 0)) { mdm_debug ("User not allowed to log in"); mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, _("\nThe system administrator " "has disabled your " "account.")); /*mdm_slave_greeter_ctl_no_ret (MDM_ERRDLG, _("Login disabled"));*/ g_free (login); g_free (passwd); g_free (ppasswd); return NULL; } #endif /* HAVE_LOGINRESTRICTIONS */ g_free (passwd); g_free (ppasswd); if ( ! mdm_slave_check_user_wants_to_log_in (login)) { g_free (login); login = NULL; goto authenticate_again; } if ( ! mdm_setup_gids (login, pwent->pw_gid)) { mdm_debug ("Cannot set user group"); mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, _("\nCannot set your user group; " "you will not be able to log in. " "Please contact your system administrator.")); g_free (login); return NULL; } #if defined (HAVE_PASSWDEXPIRED) && defined (HAVE_CHPASS) switch (passwdexpired (login, &info_msg)) { case 1 : mdm_debug ("User password has expired"); mdm_errorgui_error_box (d, GTK_MESSAGE_ERROR, _("You are required to change your password.\n" "Please choose a new one.")); g_free (info_msg); do { ret = chpass (login, response, &reEnter, &message); g_free (response); if (ret != 1) { if (ret != 0) { mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, _("\nCannot change your password; " "you will not be able to log in. " "Please try again later or contact " "your system administrator.")); } else if ((reEnter != 0) && (message)) { response = mdm_slave_greeter_ctl (MDM_NOECHO, message); if (response == NULL) response = g_strdup (""); } } g_free (message); message = NULL; } while ( ((reEnter != 0) && (ret == 0)) || (ret ==1) ); g_free (response); g_free (message); if ((ret != 0) || (reEnter != 0)) { return NULL; } #if defined (CAN_CLEAR_ADMCHG) /* The password is changed by root, clear the ADM_CHG flag in the passwd file */ ret = setpwdb (S_READ | S_WRITE); if (!ret) { upwd = getuserpw (login); if (upwd == NULL) { ret = -1; } else { upwd->upw_flags &= ~PW_ADMCHG; ret = putuserpw (upwd); if (!ret) { ret = endpwdb (); } } } if (ret) { mdm_errorgui_error_box (d, GTK_MESSAGE_WARNING, _("Your password has been changed but " "you may have to change it again. " "Please try again later or contact " "your system administrator.")); } #else /* !CAN_CLEAR_ADMCHG */ mdm_errorgui_error_box (d, GTK_MESSAGE_WARNING, _("Your password has been changed but you " "may have to change it again. Please try again " "later or contact your system administrator.")); #endif /* CAN_CLEAR_ADMCHG */ break; case 2 : mdm_debug ("User password has expired"); mdm_errorgui_error_box (d, GTK_MESSAGE_ERROR, _("Your password has expired.\n" "Only a system administrator can now change it")); g_free (info_msg); return NULL; break; case -1 : mdm_debug ("Internal error on passwdexpired"); mdm_errorgui_error_box (d, GTK_MESSAGE_ERROR, _("An internal error occurred. You will not be able to log in.\n" "Please try again later or contact your system administrator.")); g_free (info_msg); return NULL; break; default : g_free (info_msg); break; } #endif /* HAVE_PASSWDEXPIRED && HAVE_CHPASS */ return login; }
int check_passwd(stralloc *login, stralloc *authdata, struct credentials *c, int fast) { int ret; struct passwd *pw; #ifdef PW_SHADOW struct spwd *spw; #endif #ifdef AIX struct userpw *spw; #endif if (localdelivery() == 0) return NOSUCH; pw = getpwnam(login->s); if (!pw) { /* XXX: unfortunately getpwnam() hides temporary errors */ logit(32, "check_passwd: user %s not found in passwd db\n", login->s); return NOSUCH; } logit(32, "check_passwd: user %s found in passwd db\n", login->s); if (!fast) { c->gid = pw->pw_gid; c->uid = pw->pw_uid; /* * Here we don't check the home and maildir path, if a user * has a faked passwd entry, then you have a bigger problem * on your system than just a guy how can read the mail of * other users/customers. */ if (!stralloc_copys(&c->home, pw->pw_dir)) return ERRNO; if (!stralloc_0(&c->home)) return ERRNO; ret = get_local_maildir(&c->home, &c->maildir); if (ret != 0) return ret; logit(32, "get_local_maildir: maildir=%s\n", c->maildir.s); } #ifdef PW_SHADOW spw = getspnam(login->s); if (!spw) /* XXX: again, temp hidden */ return FAILED; ret = cmp_passwd((unsigned char*) authdata->s, spw->sp_pwdp); #else /* no PW_SHADOW */ #ifdef AIX spw = getuserpw(login->s); if (!spw) /* XXX: and again */ return FAILED; ret = cmp_passwd((unsigned char*) authdata->s, spw->upw_passwd); #else /* no AIX */ ret = cmp_passwd((unsigned char*) authdata->s, pw->pw_passwd); #endif /* END AIX */ #endif /* END PW_SHADOW */ logit(32, "check_pw: password compare was %s\n", ret==OK?"successful":"not successful"); return ret; }
static int _pam_auth_smb( pam_handle_t *pamh, int flags, int argc, const char **argv ) { int retval; struct passwd *pw; const char *name; char *p, *pp; int w,loop; const char *salt; char server[80],server2[80],domain[80]; char ntname[32]; int debug=0, use_first_pass=0; int nolocal=0; #ifdef HAVE_SHADOW_H struct spwd *sp; #endif /* Parse Command line options */ for (loop=0; loop<argc; loop++) { if (!strcmp(argv[loop], "debug")) debug=1; else if (!strcmp(argv[loop], "use_first_pass")) use_first_pass=1; else if (!strcmp(argv[loop], "nolocal")) nolocal=1; else syslog(LOG_AUTHPRIV | LOG_ERR, "pam_smb: Unknown Command Line Option in pam.d : %s", argv[loop]); } /* get the user'name' */ if ( (retval = pam_get_user( pamh, &name, "login: "******"x"))) { /* TODO: check if password has expired etc. */ salt = sp->sp_pwdp; } else #endif salt = pw->pw_passwd; } else return PAM_USER_UNKNOWN; /* The 'always-encrypt' method does not make sense in PAM because the framework requires return of a different error code for non-existant users -- alex */ if ( ( !pw->pw_passwd ) && ( !p ) ) if ( flags && PAM_DISALLOW_NULL_AUTHTOK ) return PAM_SUCCESS; pp = crypt(p, salt); if ( strcmp( pp, salt ) == 0 ) { if (debug) syslog(LOG_AUTHPRIV | LOG_DEBUG, "pam_smb: Local UNIX username/password pair correct."); return PAM_SUCCESS; } if (debug) { syslog (LOG_AUTHPRIV | LOG_DEBUG, "pam_smb: Local UNIX username/password check incorrect."); } } /* End of Local Section */ else { /* If Local System Authentication is switched off */ if (debug) syslog(LOG_AUTHPRIV | LOG_DEBUG,"No Local authentication done, relying on other modules for password file entry."); } w=smb_readpamconf(server,server2,domain); if (w!=0) { syslog(LOG_AUTHPRIV | LOG_ALERT, "pam_smb: Missing Configuration file : /etc/pam_smb.conf"); return PAM_AUTHINFO_UNAVAIL; } if (debug) { syslog(LOG_AUTHPRIV | LOG_DEBUG, "pam_smb: Configuration Data, Primary %s, Backup %s, Domain %s.", server, server2, domain); } w=Valid_User(ntname, p, server, server2, domain); /* Users valid user for return value 0 is success 1 and 2 indicate Network and protocol failures and 3 is not logged on */ switch (w) { case 0 : if (debug) syslog(LOG_AUTHPRIV | LOG_DEBUG, "pam_smb: Correct NT username/password pair"); return PAM_SUCCESS; break; case 1 : case 2 : return PAM_AUTHINFO_UNAVAIL; break; case 3 : default: syslog(LOG_AUTHPRIV | LOG_NOTICE, "pam_smb: Incorrect NT password for username : %s", ntname); return PAM_AUTH_ERR; break; } return PAM_AUTH_ERR; }
int sulogin_main(int argc, char **argv) { char *cp; char *device = NULL; const char *name = "root"; int timeout = 0; #define pass bb_common_bufsiz1 struct passwd pwent; struct passwd *pwd; const char * const *p; #if ENABLE_FEATURE_SHADOWPASSWDS struct spwd *spwd = NULL; #endif openlog("sulogin", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH); if (argc > 1) { if (strncmp(argv[1], "-t", 2) == 0) { if (argv[1][2] == '\0') { /* -t NN */ if (argc > 2) { timeout = atoi(argv[2]); if (argc > 3) { device = argv[3]; } } } else { /* -tNNN */ timeout = atoi(&argv[1][2]); if (argc > 2) { device = argv[2]; } } } else { device = argv[1]; } if (device) { close(0); close(1); close(2); if (open(device, O_RDWR) == 0) { dup(0); dup(0); } else { syslog(LOG_WARNING, "cannot open %s\n", device); exit(EXIT_FAILURE); } } } if (access(bb_path_passwd_file, 0) == -1) { syslog(LOG_WARNING, "No password file\n"); bb_error_msg_and_die("No password file\n"); } if (!isatty(0) || !isatty(1) || !isatty(2)) { exit(EXIT_FAILURE); } /* Clear out anything dangerous from the environment */ for (p = forbid; *p; p++) unsetenv(*p); signal(SIGALRM, catchalarm); if (!(pwd = getpwnam(name))) { syslog(LOG_WARNING, "No password entry for `root'\n"); bb_error_msg_and_die("No password entry for `root'\n"); } pwent = *pwd; #if ENABLE_FEATURE_SHADOWPASSWDS spwd = NULL; if (pwd && ((strcmp(pwd->pw_passwd, "x") == 0) || (strcmp(pwd->pw_passwd, "*") == 0))) { endspent(); spwd = getspnam(name); if (spwd) { pwent.pw_passwd = spwd->sp_pwdp; } } #endif while (1) { cp = bb_askpass(timeout, SULOGIN_PROMPT); if (!cp || !*cp) { puts("\n"); fflush(stdout); syslog(LOG_INFO, "Normal startup\n"); exit(EXIT_SUCCESS); } else { safe_strncpy(pass, cp, sizeof(pass)); memset(cp, 0, strlen(cp)); } if (strcmp(pw_encrypt(pass, pwent.pw_passwd), pwent.pw_passwd) == 0) { break; } bb_do_delay(FAIL_DELAY); puts("Login incorrect"); fflush(stdout); syslog(LOG_WARNING, "Incorrect root password\n"); } memset(pass, 0, strlen(pass)); signal(SIGALRM, SIG_DFL); puts("Entering System Maintenance Mode\n"); fflush(stdout); syslog(LOG_INFO, "System Maintenance Mode\n"); #if ENABLE_SELINUX renew_current_security_context(); #endif run_shell(pwent.pw_shell, 1, 0, 0); return (0); }
void shadowauth(const char *myname, int persist) { const char *hash; char *encrypted; struct passwd *pw; char *challenge, *response, rbuf[1024], cbuf[128]; #ifdef USE_TIMESTAMP int fd = -1; int valid = 0; if (persist) fd = timestamp_open(&valid, 5 * 60); if (fd != -1 && valid == 1) goto good; #else (void) persist; #endif if ((pw = getpwnam(myname)) == NULL) err(1, "getpwnam"); hash = pw->pw_passwd; if (hash[0] == 'x' && hash[1] == '\0') { struct spwd *sp; if ((sp = getspnam(myname)) == NULL) errx(1, "Authorization failed"); hash = sp->sp_pwdp; } else if (hash[0] != '*') { errx(1, "Authorization failed"); } char host[HOST_NAME_MAX + 1]; if (gethostname(host, sizeof(host))) snprintf(host, sizeof(host), "?"); snprintf(cbuf, sizeof(cbuf), "\rdoas (%.32s@%.32s) password: "******"tty required for %s", myname); errx(1, "a tty is required"); } if (response == NULL) err(1, "readpassphrase"); if ((encrypted = crypt(response, hash)) == NULL) { explicit_bzero(rbuf, sizeof(rbuf)); errx(1, "Authorization failed"); } explicit_bzero(rbuf, sizeof(rbuf)); if (strcmp(encrypted, hash) != 0) { syslog(LOG_AUTHPRIV | LOG_NOTICE, "failed auth for %s", myname); errx(1, "Authorization failed"); } #ifdef USE_TIMESTAMP good: if (fd != -1) { timestamp_set(fd, 5 * 60); close(fd); } #endif }
void pw_unix_check(AuthResult * const result, const char *account, const char *password, const struct sockaddr_storage * const sa, const struct sockaddr_storage * const peer) { const char *cpwd = NULL; struct passwd pw, *pw_; #ifdef USE_SHADOW struct spwd *spw; #endif char *dir = NULL; (void) sa; (void) peer; result->auth_ok = 0; if ((pw_ = getpwnam(account)) == NULL) { return; } pw = *pw_; result->auth_ok--; #ifdef HAVE_SETUSERSHELL if (pw.pw_shell == NULL) { return; } if (strcasecmp(pw.pw_shell, FAKE_SHELL) != 0) { const char *shell; setusershell(); while ((shell = (char *) getusershell()) != NULL && strcmp(pw.pw_shell, shell) != 0); endusershell(); if (shell == NULL) { return; } } #endif if ((dir = strdup(pw.pw_dir)) == NULL) { return; } #ifdef USE_SHADOW if ((((pw.pw_passwd)[0] == 'x' && (pw.pw_passwd)[1] == 0) || ((pw.pw_passwd)[0] == '#' && (pw.pw_passwd)[1] == '#' && strcmp(pw.pw_passwd + 2, account) == 0)) && (spw = getspnam(account)) != NULL && spw->sp_pwdp != NULL) { cpwd = spw->sp_pwdp[0] == '@' ? NULL : spw->sp_pwdp; if (spw->sp_expire > 0 || spw->sp_max > 0) { long today = time(NULL) / (24L * 60L * 60L); if (spw->sp_expire > 0 && spw->sp_expire < today) { goto bye; /* account expired */ } if (spw->sp_max > 0 && spw->sp_lstchg > 0 && (spw->sp_lstchg + spw->sp_max < today)) { goto bye; /* password expired */ } } } else #endif { cpwd = pw.pw_passwd; } { const char *crypted; if (cpwd == NULL || (crypted = (const char *) crypt(password, cpwd)) == NULL || strcmp(cpwd, crypted) != 0) { goto bye; } } result->uid = pw.pw_uid; result->gid = pw.pw_gid; result->dir = dir; result->slow_tilde_expansion = 0; result->auth_ok = -result->auth_ok; return; bye: free(dir); }
int post_passwd_server(int client, char *ibuf, int len, char *torken) { if(torken){ return response_state(client, NO_SERVICE, err_msg[NO_SERVICE]); } ezxml_t root = NULL, name=NULL, oldpasswd=NULL, passwd=NULL; root = ezxml_parse_str(ibuf, len); if(!root){ ezxml_free(root); return response_state(client, FORMAT_ERR, err_msg[FORMAT_ERR]); } if(root && *ezxml_error(root)) { ezxml_free(root); return response_state(client, FORMAT_ERR, err_msg[FORMAT_ERR]); } name = ezxml_child(root, "USER_NAME"); oldpasswd = ezxml_child(root, "OLD_PASSWD"); passwd = ezxml_child(root, "PASSWD"); if(!name || !name->txt[0] || !oldpasswd ||!oldpasswd->txt[0] || !passwd || !passwd->txt[0]){ return response_state(client, FORMAT_ERR, "Need name oldpasswd and new passwd" ); } char salt[128] = {0}, *ptr = 0; struct spwd *pw = getspnam(name->txt); if(!pw){ return response_state(client, SYS_ERR, "Invalid name"); } ptr = strchr(pw->sp_pwdp+1, '$'); if(!ptr){ return response_state(client, SYS_ERR, "Unkonw passwd format"); } ptr = strchr(ptr+1, '$'); if(!ptr){ return response_state(client, SYS_ERR, "Unkonw passwd format"); } strncpy(salt, pw->sp_pwdp, ptr-pw->sp_pwdp); ptr = crypt(oldpasswd->txt, salt); if(strcmp(ptr, pw->sp_pwdp)){ return response_state(client, SYS_ERR, "Invalid old passwd"); } char cmd[XMLLEN] = {0}; snprintf(cmd, sizeof(cmd), "echo -e '%s\n%s'|/usr/bin/passwd", passwd->txt, passwd->txt); system(cmd); return 0; }
int main(int argc, char **argv) { int i, optidx = 0; char *su_user; struct passwd *su_info; struct passwd *login_info; struct passwd *pwd; char *shell; int ok = 0; setprogname (argv[0]); if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) usage(1); for (i=0; i < optidx; i++) if (strcmp(argv[i], "-") == 0) { full_login = 1; break; } if(help_flag) usage(0); if(version_flag) { print_version(NULL); exit(0); } if(optidx >= argc) su_user = "******"; else su_user = argv[optidx++]; if (!issuid() && getuid() != 0) warnx("Not setuid and you are not root, expect this to fail"); pwd = k_getpwnam(su_user); if(pwd == NULL) errx (1, "unknown login %s", su_user); if (pwd->pw_uid == 0 && strcmp ("root", su_user) != 0) { syslog (LOG_ALERT, "NIS attack, user %s has uid 0", su_user); errx (1, "unknown login %s", su_user); } su_info = dup_info(pwd); if (su_info == NULL) errx (1, "malloc: out of memory"); pwd = getpwuid(getuid()); if(pwd == NULL) errx(1, "who are you?"); login_info = dup_info(pwd); if (login_info == NULL) errx (1, "malloc: out of memory"); if(env_flag) shell = login_info->pw_shell; else shell = su_info->pw_shell; if(shell == NULL || *shell == '\0') shell = _PATH_BSHELL; #ifdef KRB5 if(kerberos_flag && ok == 0 && krb5_verify(login_info, su_info, kerberos_instance) == 0) ok = 5; #endif if(ok == 0 && login_info->pw_uid && verify_unix(login_info, su_info) != 0) { printf("Sorry!\n"); exit(1); } #ifdef HAVE_GETSPNAM { struct spwd *sp; long today; sp = getspnam(su_info->pw_name); if (sp != NULL) { today = time(0)/(24L * 60 * 60); if (sp->sp_expire > 0) { if (today >= sp->sp_expire) { if (login_info->pw_uid) errx(1,"Your account has expired."); else printf("Your account has expired."); } else if (sp->sp_expire - today < 14) printf("Your account will expire in %d days.\n", (int)(sp->sp_expire - today)); } if (sp->sp_max > 0) { if (today >= sp->sp_lstchg + sp->sp_max) { if (login_info->pw_uid) errx(1,"Your password has expired. Choose a new one."); else printf("Your password has expired. Choose a new one."); } else if (today >= sp->sp_lstchg + sp->sp_max - sp->sp_warn) printf("Your account will expire in %d days.\n", (int)(sp->sp_lstchg + sp->sp_max -today)); } } } #endif { char *tty = ttyname (STDERR_FILENO); if (tty) syslog (LOG_NOTICE | LOG_AUTH, "%s to %s on %s", login_info->pw_name, su_info->pw_name, tty); else syslog (LOG_NOTICE | LOG_AUTH, "%s to %s", login_info->pw_name, su_info->pw_name); } if(!env_flag) { if(full_login) { char *t = getenv ("TERM"); char **newenv = NULL; int j; i = read_environment(_PATH_ETC_ENVIRONMENT, &newenv); environ = malloc ((10 + i) * sizeof (char *)); if (environ == NULL) err (1, "malloc"); environ[0] = NULL; for (j = 0; j < i; j++) { char *p = strchr(newenv[j], '='); if (p == NULL) errx(1, "environment '%s' missing '='", newenv[j]); *p++ = 0; esetenv (newenv[j], p, 1); } free(newenv); esetenv ("PATH", _PATH_DEFPATH, 1); if (t) esetenv ("TERM", t, 1); if (chdir (su_info->pw_dir) < 0) errx (1, "no directory"); } if (full_login || su_info->pw_uid) esetenv ("USER", su_info->pw_name, 1); esetenv("HOME", su_info->pw_dir, 1); esetenv("SHELL", shell, 1); } { char **new_argv; char *p; p = strrchr(shell, '/'); if(p) p++; else p = shell; if (strcmp(p, "csh") != 0) csh_f_flag = 0; new_argv = malloc(((cmd ? 2 : 0) + 1 + argc - optidx + 1 + csh_f_flag) * sizeof(*new_argv)); if (new_argv == NULL) err (1, "malloc"); i = 0; if(full_login) { if (asprintf(&new_argv[i++], "-%s", p) == -1) errx (1, "malloc"); } else new_argv[i++] = p; if (cmd) { new_argv[i++] = "-c"; new_argv[i++] = cmd; } if (csh_f_flag) new_argv[i++] = "-f"; for (argv += optidx; *argv; ++argv) new_argv[i++] = *argv; new_argv[i] = NULL; if(setgid(su_info->pw_gid) < 0) err(1, "setgid"); if (initgroups (su_info->pw_name, su_info->pw_gid) < 0) err (1, "initgroups"); if(setuid(su_info->pw_uid) < 0 || (su_info->pw_uid != 0 && setuid(0) == 0)) err(1, "setuid"); #ifdef KRB5 if (ok == 5) krb5_start_session(); #endif execve(shell, new_argv, environ); } exit(1); }
static int process_root_password(void) { static const char table[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" "./"; struct spwd item = { .sp_namp = (char*) "root", .sp_min = -1, .sp_max = -1, .sp_warn = -1, .sp_inact = -1, .sp_expire = -1, .sp_flag = (unsigned long) -1, /* this appears to be what everybody does ... */ }; _cleanup_close_ int lock = -1; char salt[3+16+1+1]; uint8_t raw[16]; unsigned i; char *j; const char *etc_shadow; int r; etc_shadow = prefix_roota(arg_root, "/etc/shadow"); if (laccess(etc_shadow, F_OK) >= 0) return 0; mkdir_parents(etc_shadow, 0755); lock = take_etc_passwd_lock(arg_root); if (lock < 0) return log_error_errno(lock, "Failed to take a lock: %m"); if (arg_copy_root_password && arg_root) { struct spwd *p; errno = 0; p = getspnam("root"); if (p || errno != ENOENT) { if (!p) { if (!errno) errno = EIO; return log_error_errno(errno, "Failed to find shadow entry for root: %m"); } r = write_root_shadow(etc_shadow, p); if (r < 0) return log_error_errno(r, "Failed to write %s: %m", etc_shadow); log_info("%s copied.", etc_shadow); return 0; } } r = prompt_root_password(); if (r < 0) return r; if (!arg_root_password) return 0; /* Insist on the best randomness by setting RANDOM_BLOCK, this is about keeping passwords secret after all. */ r = genuine_random_bytes(raw, 16, RANDOM_BLOCK); if (r < 0) return log_error_errno(r, "Failed to get salt: %m"); /* We only bother with SHA512 hashed passwords, the rest is legacy, and we don't do legacy. */ assert_cc(sizeof(table) == 64 + 1); j = stpcpy(salt, "$6$"); for (i = 0; i < 16; i++) j[i] = table[raw[i] & 63]; j[i++] = '$'; j[i] = 0; errno = 0; item.sp_pwdp = crypt(arg_root_password, salt); if (!item.sp_pwdp) { if (!errno) errno = EINVAL; return log_error_errno(errno, "Failed to encrypt password: %m"); } item.sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY); r = write_root_shadow(etc_shadow, &item); if (r < 0) return log_error_errno(r, "Failed to write %s: %m", etc_shadow); log_info("%s written.", etc_shadow); return 0; } static int help(void) { _cleanup_free_ char *link = NULL; int r; r = terminal_urlify_man("systemd-firstboot", "1", &link); if (r < 0) return log_oom(); printf("%s [OPTIONS...]\n\n" "Configures basic settings of the system.\n\n" " -h --help Show this help\n" " --version Show package version\n" " --root=PATH Operate on an alternate filesystem root\n" " --locale=LOCALE Set primary locale (LANG=)\n" " --locale-messages=LOCALE Set message locale (LC_MESSAGES=)\n" " --keymap=KEYMAP Set keymap\n" " --timezone=TIMEZONE Set timezone\n" " --hostname=NAME Set host name\n" " --machine-ID=ID Set machine ID\n" " --root-password=PASSWORD Set root password\n" " --root-password-file=FILE Set root password from file\n" " --prompt-locale Prompt the user for locale settings\n" " --prompt-keymap Prompt the user for keymap settings\n" " --prompt-timezone Prompt the user for timezone\n" " --prompt-hostname Prompt the user for hostname\n" " --prompt-root-password Prompt the user for root password\n" " --prompt Prompt for all of the above\n" " --copy-locale Copy locale from host\n" " --copy-keymap Copy keymap from host\n" " --copy-timezone Copy timezone from host\n" " --copy-root-password Copy root password from host\n" " --copy Copy locale, keymap, timezone, root password\n" " --setup-machine-id Generate a new random machine ID\n" "\nSee the %s for details.\n" , program_invocation_short_name , link ); return 0; }
/* * Check if the user is allowed to log in via ssh. If user is listed * in DenyUsers or one of user's groups is listed in DenyGroups, false * will be returned. If AllowUsers isn't empty and user isn't listed * there, or if AllowGroups isn't empty and one of user's groups isn't * listed there, false will be returned. * If the user's shell is not executable, false will be returned. * Otherwise true is returned. */ int allowed_user(struct passwd * pw) { struct stat st; const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL; u_int i; #ifdef USE_SHADOW struct spwd *spw = NULL; #endif /* Shouldn't be called if pw is NULL, but better safe than sorry... */ if (!pw || !pw->pw_name) return 0; #ifdef USE_SHADOW if (!options.use_pam) spw = getspnam(pw->pw_name); #ifdef HAS_SHADOW_EXPIRE if (!options.use_pam && spw != NULL && auth_shadow_acctexpired(spw)) return 0; #endif /* HAS_SHADOW_EXPIRE */ #endif /* USE_SHADOW */ /* grab passwd field for locked account check */ passwd = pw->pw_passwd; #ifdef USE_SHADOW if (spw != NULL) #ifdef USE_LIBIAF passwd = get_iaf_password(pw); #else passwd = spw->sp_pwdp; #endif /* USE_LIBIAF */ #endif /* check for locked account */ if (!options.use_pam && passwd && *passwd) { int locked = 0; #ifdef LOCKED_PASSWD_STRING if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0) locked = 1; #endif #ifdef LOCKED_PASSWD_PREFIX if (strncmp(passwd, LOCKED_PASSWD_PREFIX, strlen(LOCKED_PASSWD_PREFIX)) == 0) locked = 1; #endif #ifdef LOCKED_PASSWD_SUBSTR if (strstr(passwd, LOCKED_PASSWD_SUBSTR)) locked = 1; #endif #ifdef USE_LIBIAF free((void *) passwd); #endif /* USE_LIBIAF */ if (locked) { logit("User %.100s not allowed because account is locked", pw->pw_name); return 0; } } /* * Deny if shell does not exist or is not executable unless we * are chrooting. */ if (options.chroot_directory == NULL || strcasecmp(options.chroot_directory, "none") == 0) { char *shell = xstrdup((pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */ if (stat(shell, &st) != 0) { logit("User %.100s not allowed because shell %.100s " "does not exist", pw->pw_name, shell); xfree(shell); return 0; } if (S_ISREG(st.st_mode) == 0 || (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) { logit("User %.100s not allowed because shell %.100s " "is not executable", pw->pw_name, shell); xfree(shell); return 0; } xfree(shell); } if (options.num_deny_users > 0 || options.num_allow_users > 0 || options.num_deny_groups > 0 || options.num_allow_groups > 0) { hostname = get_canonical_hostname(options.use_dns); ipaddr = get_remote_ipaddr(); } /* Return false if user is listed in DenyUsers */ if (options.num_deny_users > 0) { for (i = 0; i < options.num_deny_users; i++) if (match_user(pw->pw_name, hostname, ipaddr, options.deny_users[i])) { logit("User %.100s from %.100s not allowed " "because listed in DenyUsers", pw->pw_name, hostname); return 0; } } /* Return false if AllowUsers isn't empty and user isn't listed there */ if (options.num_allow_users > 0) { for (i = 0; i < options.num_allow_users; i++) if (match_user(pw->pw_name, hostname, ipaddr, options.allow_users[i])) break; /* i < options.num_allow_users iff we break for loop */ if (i >= options.num_allow_users) { logit("User %.100s from %.100s not allowed because " "not listed in AllowUsers", pw->pw_name, hostname); return 0; } } if (options.num_deny_groups > 0 || options.num_allow_groups > 0) { /* Get the user's group access list (primary and supplementary) */ if (ga_init(pw->pw_name, pw->pw_gid) == 0) { logit("User %.100s from %.100s not allowed because " "not in any group", pw->pw_name, hostname); return 0; } /* Return false if one of user's groups is listed in DenyGroups */ if (options.num_deny_groups > 0) if (ga_match(options.deny_groups, options.num_deny_groups)) { ga_free(); logit("User %.100s from %.100s not allowed " "because a group is listed in DenyGroups", pw->pw_name, hostname); return 0; } /* * Return false if AllowGroups isn't empty and one of user's groups * isn't listed there */ if (options.num_allow_groups > 0) if (!ga_match(options.allow_groups, options.num_allow_groups)) { ga_free(); logit("User %.100s from %.100s not allowed " "because none of user's groups are listed " "in AllowGroups", pw->pw_name, hostname); return 0; } ga_free(); } #ifdef CUSTOM_SYS_AUTH_ALLOWED_USER if (!sys_auth_allowed_user(pw, &loginmsg)) return 0; #endif /* We found no reason not to let this user try to log on... */ return 1; }
static int plogin(char *user, char *passwd, char **msg, int *msglen) { #ifdef USE_PAM struct pam_conv pam_conversation; pam_handle_t *pamh; int pam_error; /* * Fill the pam_conversion structure */ memset (&pam_conversation, '\0', sizeof (struct pam_conv)); pam_conversation.conv = &pam_conv; pam_error = pam_start ("ppp", user, &pam_conversation, &pamh); if (pam_error != PAM_SUCCESS) { *msg = MY_PAM_STRERROR (pam_error); return UPAP_AUTHNAK; } /* * Define the fields for the credintial validation */ pam_set_item (pamh, PAM_TTY, devnam); PAM_username = user; PAM_password = passwd; /* * Validate the user */ pam_error = pam_authenticate (pamh, PAM_SILENT); if (pam_error == PAM_SUCCESS) { pam_error = pam_acct_mgmt (pamh, PAM_SILENT); /* start a session for this user. Session closed when link ends. */ if (pam_error == PAM_SUCCESS) pam_open_session (pamh, PAM_SILENT); } *msg = MY_PAM_STRERROR (pam_error); PAM_username = PAM_password = ""; /* * Clean up the mess */ pam_end (pamh, pam_error); if (pam_error != PAM_SUCCESS) return UPAP_AUTHNAK; /* * Use the non-PAM methods directly */ #else /* #ifdef USE_PAM */ struct passwd *pw; struct utmp utmp; struct timeval tp; char *tty; #ifdef HAS_SHADOW struct spwd *spwd; struct spwd *getspnam(); #endif pw = getpwnam(user); endpwent(); if (pw == NULL) { return (UPAP_AUTHNAK); } /* * Check that the user is not listed in /etc/ppp/ppp.deny * and that the user's shell is listed in /etc/ppp/ppp.shells * if /etc/ppp/ppp.shells exists. */ if (checkfile(_PATH_PPPDENY, user) == 1) { syslog(LOG_WARNING, "upap user %s: login denied in %s", user, _PATH_PPPDENY); return (UPAP_AUTHNAK); } if (checkfile(_PATH_PPPSHELLS, pw->pw_shell) == 0) { syslog(LOG_WARNING, "upap user %s: shell %s not in %s", user, pw->pw_shell, _PATH_PPPSHELLS); return (UPAP_AUTHNAK); } #ifdef HAS_SHADOW spwd = getspnam(user); endspent(); if (spwd) { /* check the age of the password entry */ long now = time(NULL) / 86400L; if ((spwd->sp_expire > 0 && now >= spwd->sp_expire) || ((spwd->sp_max >= 0 && spwd->sp_max < 10000) && spwd->sp_lstchg >= 0 && now >= spwd->sp_lstchg + spwd->sp_max)) { syslog(LOG_WARNING, "Password for %s has expired", user); return (UPAP_AUTHNAK); } pw->pw_passwd = spwd->sp_pwdp; } #endif /* * If no passwd, don't let them login. */ if (pw->pw_passwd == NULL || *pw->pw_passwd == '\0' || strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd) != 0) return (UPAP_AUTHNAK); if (pw->pw_expire) { gettimeofday(&tp, NULL); if (tp.tv_sec >= pw->pw_expire) { syslog(LOG_INFO, "pap user %s account expired", user); return (UPAP_AUTHNAK); } } /* These functions are not enabled for PAM. The reason for this is that */ /* there is not necessarily a "passwd" entry for this user. That is */ /* real purpose of 'PAM' -- to virtualize the account data from the */ /* application. If you want to do the same thing, write the entry in */ /* the 'session' hook. */ /* Log in wtmp and utmp using login() */ tty = devnam; if (strncmp(tty, _PATH_DEV, sizeof _PATH_DEV - 1) == 0) tty += 5; if (logout(tty)) /* Already entered (by login?) */ logwtmp(tty, "", ""); #if defined(_PATH_LASTLOG) { struct lastlog ll; int fd; if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { lseek(fd, (off_t)(pw->pw_uid * sizeof(ll)), SEEK_SET); memset((void *)&ll, 0, sizeof(ll)); time(&ll.ll_time); strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); write(fd, (char *)&ll, sizeof(ll)); close(fd); } } #endif memset((void *)&utmp, 0, sizeof(utmp)); time(&utmp.ut_time); strncpy(utmp.ut_name, user, sizeof(utmp.ut_name)); strncpy(utmp.ut_host, ":PPP", sizeof(utmp.ut_host)); strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); login(&utmp); /* This logs us in wtmp too */ #endif /* #ifdef USE_PAM */ syslog(LOG_INFO, "user %s logged in", user); logged_in = TRUE; return (UPAP_AUTHACK); }
void auth_client(struct fcrondyn_cl *client) /* check client identity */ { char *pass_cry = NULL; char *pass_sys = NULL; char *pass_str = NULL; #ifdef HAVE_LIBSHADOW struct spwd *pass_sp = NULL; if ( (pass_sp = getspnam((char *) client->fcl_cmd )) == NULL ) { error_e("could not getspnam %s", (char *) client->fcl_cmd); send(client->fcl_sock_fd, "0", sizeof("0"), 0); return; } pass_sys = pass_sp->sp_pwdp; #else struct passwd *pass = NULL; if ( (pass = getpwnam((char *) client->fcl_cmd )) == NULL ) { error_e("could not getpwnam %s", (char *) client->fcl_cmd); send(client->fcl_sock_fd, "0", sizeof("0"), 0); return; } pass_sys = pass->pw_passwd; #endif /* */ debug("auth_client() : socket : %d", client->fcl_sock_fd); /* */ /* we need to limit auth failures : otherwise fcron may be used to "read" * shadow password !!! (or to crack it using a test-all-possible-password attack) */ if (auth_fail > 0 && auth_nofail_since + AUTH_WAIT <= now ) /* no auth time exceeded : set counter to 0 */ auth_fail = 0; if (auth_fail >= MAX_AUTH_FAIL) { error("Too many authentication failures : try to connect later."); send(client->fcl_sock_fd, "0", sizeof("0"), 0); auth_fail = auth_nofail_since = 0; return; } /* password is stored after user name */ pass_str = &( (char *)client->fcl_cmd ) [ strlen( (char*)client->fcl_cmd ) + 1 ]; if ( (pass_cry = crypt(pass_str, pass_sys)) == NULL ) { error_e("could not crypt()"); send(client->fcl_sock_fd, "0", sizeof("0"), 0); return; } /* debug("pass_sp->sp_pwdp : %s", pass_sp->sp_pwdp); */ /* debug("pass_cry : %s", pass_cry); */ if (strcmp(pass_cry, pass_sys) == 0) { client->fcl_user = strdup2( (char *) client->fcl_cmd ); send(client->fcl_sock_fd, "1", sizeof("1"), 0); } else { auth_fail++; auth_nofail_since = now; error("Invalid passwd for %s from socket %d", (char *) client->fcl_cmd, client->fcl_sock_fd); send(client->fcl_sock_fd, "0", sizeof("0"), 0); } }
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char *argv[]) { #ifndef OPENPAM struct pam_conv *conv; struct pam_message msg; const struct pam_message *msgp; struct pam_response *resp; #endif struct spwd *spwd; const char *user; char *crypt_password, *password; int pam_err, retry; (void)argc; (void)argv; /* identify user */ if ((pam_err = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) return (pam_err); if ((spwd = getspnam(user)) == NULL) return (PAM_USER_UNKNOWN); /* get password */ #ifndef OPENPAM pam_err = pam_get_item(pamh, PAM_CONV, (const void **)&conv); if (pam_err != PAM_SUCCESS) return (PAM_SYSTEM_ERR); msg.msg_style = PAM_PROMPT_ECHO_OFF; msg.msg = password_prompt; msgp = &msg; #endif for (retry = 0; retry < 3; ++retry) { #ifdef OPENPAM pam_err = pam_get_authtok(pamh, PAM_AUTHTOK, (const char **)&password, NULL); #else resp = NULL; pam_err = (*conv->conv)(1, &msgp, &resp, conv->appdata_ptr); if (resp != NULL) { if (pam_err == PAM_SUCCESS) password = resp->resp; else free(resp->resp); free(resp); } #endif if (pam_err == PAM_SUCCESS) break; } if (pam_err == PAM_CONV_ERR) return (pam_err); if (pam_err != PAM_SUCCESS) return (PAM_AUTH_ERR); /* compare passwords */ if ((!spwd->sp_pwdp[0] && (flags & PAM_DISALLOW_NULL_AUTHTOK)) || (crypt_password = crypt(password, spwd->sp_pwdp)) == NULL || strcmp(crypt_password, spwd->sp_pwdp) != 0) pam_err = PAM_AUTH_ERR; else pam_err = PAM_SUCCESS; #ifndef OPENPAM free(password); #endif return (pam_err); }