📄 ftpd.c
字号:
#else setspent(); if ((spw = getspnam(p->pw_name)) != NULL) {#endif int expired = 0; /*XXX Does this work on all Shadow Password Implementations? */ /* it is supposed to work on Solaris 2.x */ time_t now; long today; now = time((time_t *) 0); today = now / (60 * 60 * 24); if ((spw->sp_expire > 0) && (spw->sp_expire < today)) expired++; if ((spw->sp_max > 0) && (spw->sp_lstchg > 0) && (spw->sp_lstchg + spw->sp_max < today)) expired++; free(save.pw_passwd); save.pw_passwd = sgetsave(expired ? "" : spw->sp_pwdp); }/* Don't overwrite the password if the shadow read fails, getpwnam() is NIS aware but getspnam() is not. *//* Shadow passwords are optional on Linux. --marekm */#if !defined(LINUX) && !defined(UNIXWARE) else { free(save.pw_passwd); save.pw_passwd = sgetsave(""); }#endif/* marekm's fix for linux proc file system shadow passwd exposure problem */#ifndef OTHER_PASSWD endspent();#endif }#endif save.pw_gecos = sgetsave(p->pw_gecos); save.pw_dir = sgetsave(p->pw_dir); save.pw_shell = sgetsave(p->pw_shell);#ifdef M_UNIX ret = &save; DONE: endpwent();#endif#if defined(SecureWare) || defined(HPUX_10_TRUSTED) endprpwent();#endif#ifdef M_UNIX return (ret);#else return (&save);#endif}#if defined(SKEY) && !defined(__NetBSD__)/* * From Wietse Venema, Eindhoven University of Technology. *//* skey_challenge - additional password prompt stuff */char *skey_challenge(char *name, struct passwd *pwd, int pwok){ static char buf[128]; char sbuf[40]; struct skey skey; /* Display s/key challenge where appropriate. */ if (pwd == NULL || skeychallenge(&skey, pwd->pw_name, sbuf)) sprintf(buf, "Password required for %s.", name); else sprintf(buf, "%s %s for %s.", sbuf, pwok ? "allowed" : "required", name); return (buf);}#endifint login_attempts; /* number of failed login attempts */int askpasswd; /* had user command, ask for passwd */#ifndef HELP_CRACKERSint DenyLoginAfterPassword;char DelayedMessageFile[MAXPATHLEN];extern void pr_mesg(int msgcode, char *msgfile);#endif#if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER)static int defaultserver_allow(const char *username){ struct aclmember *entry = NULL; int which; while (getaclentry("defaultserver", &entry)) if (ARG0 && !strcasecmp(ARG0, "allow")) for (which = 1; (which < MAXARGS) && ARG[which]; which++) if (!strcasecmp(username, ARG[which]) || !strcmp("*", ARG[which])) return (1); return (0);}static int defaultserver_deny(const char *username){ struct aclmember *entry = NULL; int which; while (getaclentry("defaultserver", &entry)) if (ARG0 && !strcasecmp(ARG0, "deny")) for (which = 1; (which < MAXARGS) && ARG[which]; which++) if (!strcasecmp(username, ARG[which]) || !strcmp("*", ARG[which])) return (1); return (0);}static int defaultserver_private(void){ struct aclmember *entry = NULL; while (getaclentry("defaultserver", &entry)) if (ARG0 && !strcasecmp(ARG0, "private")) return (1); return (0);}#endif/* USER command. Sets global passwd pointer pw if named account exists and is * acceptable; sets askpasswd if a PASS command is expected. If logged in * previously, need to reset state. If name is "ftp" or "anonymous", the * name is not in _PATH_FTPUSERS, and ftp account exists, set anonymous and * pw, then just return. If account doesn't exist, ask for passwd anyway. * Otherwise, check user requesting login privileges. Disallow anyone who * does not have a standard shell as returned by getusershell(). Disallow * anyone mentioned in the file _PATH_FTPUSERS to allow people such as root * and uucp to be avoided. *//* char *getusershell(); */void user(char *name){ char *cp; char *shell;#ifdef BSD_AUTH char *auth;#endif/* H* fix: if we're logged in at all, we can't log in again. */ if (logged_in) {#ifdef VERBOSE_ERROR_LOGING syslog(LOG_NOTICE, "FTP LOGIN REFUSED (already logged in as %s) FROM %s, %s", pw->pw_name, remoteident, name);#endif reply(530, "Already logged in."); return; }#ifndef HELP_CRACKERS askpasswd = 1; DenyLoginAfterPassword = 0; DelayedMessageFile[0] = '\0';#endif#ifdef BSD_AUTH if ((auth = strchr(name, ':'))) *auth++ = 0;#endif#ifdef HOST_ACCESS /* 19-Mar-93 BM */ if (!rhost_ok(name, remotehost, remoteaddr)) {#ifndef HELP_CRACKERS DenyLoginAfterPassword = 1; syslog(LOG_NOTICE, "FTP LOGIN REFUSED (name in %s) FROM %s, %s", _PATH_FTPHOSTS, remoteident, name);#else reply(530, "User %s access denied.", name); syslog(LOG_NOTICE, "FTP LOGIN REFUSED (name in %s) FROM %s, %s", _PATH_FTPHOSTS, remoteident, name); return;#endif }#endif#ifdef LOG_FAILED /* 06-Nov-92 EHK */ strncpy(the_user, name, MAXUSERNAMELEN - 1);#endif anonymous = 0; acl_remove(); if (!strcasecmp(name, "ftp") || !strcasecmp(name, "anonymous")) { struct aclmember *entry = NULL; int machineok = 1; char guestservername[MAXHOSTNAMELEN]; guestservername[0] = '\0';#ifdef NO_ANONYMOUS_ACCESS reply(530, "Anonymous FTP access denied."); syslog(LOG_NOTICE, "FTP LOGIN REFUSED (anonymous ftp not supported) FROM %s, %s", remoteident, name); return;#else#if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER) if (!virtual_mode && defaultserver_private()) {#ifndef HELP_CRACKERS DenyLoginAfterPassword = 1; syslog(LOG_NOTICE, "FTP LOGIN REFUSED (anonymous ftp denied on default server) FROM %s, %s", remoteident, name);#else reply(530, "User %s access denied.", name); syslog(LOG_NOTICE, "FTP LOGIN REFUSED (anonymous ftp denied on default server) FROM %s, %s", remoteident, name); return;#endif }#endif if (checkuser("ftp") || checkuser("anonymous")) {#ifndef HELP_CRACKERS DenyLoginAfterPassword = 1; syslog(LOG_NOTICE, "FTP LOGIN REFUSED (ftp in %s) FROM %s, %s", _PATH_FTPUSERS, remoteident, name);#else reply(530, "User %s access denied.", name); syslog(LOG_NOTICE, "FTP LOGIN REFUSED (ftp in %s) FROM %s, %s", _PATH_FTPUSERS, remoteident, name); return;#endif /* ** Algorithm used: ** - if no "guestserver" directive is present, ** anonymous access is allowed, for backward compatibility. ** - if a "guestserver" directive is present, ** anonymous access is restricted to the machines listed, ** usually the machine whose CNAME on the current domain ** is "ftp"... ** ** the format of the "guestserver" line is ** guestserver [<machine1> [<machineN>]] ** that is, "guestserver" will forbid anonymous access on all machines ** while "guestserver ftp inf" will allow anonymous access on ** the two machines whose CNAMES are "ftp.enst.fr" and "inf.enst.fr". ** ** if anonymous access is denied on the current machine, ** the user will be asked to use the first machine listed (if any) ** on the "guestserver" line instead: ** 530- Guest login not allowed on this machine, ** connect to ftp.enst.fr instead. ** ** -- <Nicolas.Pioch@enst.fr> */ } else if (getaclentry("guestserver", &entry) && ARG0 && (int) strlen(ARG0) > 0) { struct hostent *tmphostent; /* ** if a "guestserver" line is present, ** default is not to allow guest logins */ machineok = 0; if (hostname[0] && ((tmphostent = gethostbyname(hostname)))) { /* ** hostname is the only first part of the FQDN ** this may or may not correspond to the h_name value ** (machines with more than one IP#, CNAMEs...) ** -> need to fix that, calling gethostbyname on hostname ** ** WARNING! ** for SunOS 4.x, you need to have a working resolver in the libc ** for CNAMES to work properly. ** If you don't, add "-lresolv" to the libraries before compiling! */ char dns_localhost[MAXHOSTNAMELEN]; int machinecount; strncpy(dns_localhost, tmphostent->h_name, sizeof(dns_localhost)); dns_localhost[sizeof(dns_localhost) - 1] = '\0'; for (machinecount = 0; entry->arg[machinecount] && (entry->arg[machinecount])[0]; machinecount++) { if ((tmphostent = gethostbyname(entry->arg[machinecount]))) { /* ** remember the name of the first machine for redirection */ if ((!machinecount) && tmphostent->h_name) { strncpy(guestservername, entry->arg[machinecount], sizeof(guestservername)); guestservername[sizeof(guestservername) - 1] = '\0'; } if (!strcasecmp(tmphostent->h_name, dns_localhost)) { machineok++; break; } } } } } if (!machineok) { if (guestservername[0]) reply(530, "Guest login not allowed on this machine, connect to %s instead.", guestservername); else reply(530, "Guest login not allowed on this machine."); syslog(LOG_NOTICE, "FTP LOGIN REFUSED (localhost not in guestservers) FROM %s, %s", remoteident, name); /* End of the big patch -- Nap */ } else if ((pw = sgetpwnam("ftp")) != NULL) { anonymous = 1; /* for the access_ok call */ if (access_ok(530) < 1) {#ifndef HELP_CRACKERS DenyLoginAfterPassword = 1; syslog(LOG_NOTICE, "FTP LOGIN REFUSED (access denied) FROM %s, %s", remoteident, name); reply(331, "Guest login ok, send your complete e-mail address as password.");#else reply(530, "User %s access denied.", name); syslog(LOG_NOTICE, "FTP LOGIN REFUSED (access denied) FROM %s, %s", remoteident, name); dologout(0);#endif } else { askpasswd = 1;/* H* fix: obey use_accessfile a little better. This way, things set on the command line [like xferlog stuff] don't get stupidly overridden. XXX: all these checks maybe should be in acl.c and access.c */ if (use_accessfile) acl_setfunctions(); reply(331, "Guest login ok, send your complete e-mail address as password."); } } else {#ifndef HELP_CRACKERS DenyLoginAfterPassword = 1; reply(331, "Guest login ok, send your complete e-mail address as password."); syslog(LOG_NOTICE, "FTP LOGIN REFUSED (ftp not in /etc/passwd) FROM %s, %s", remoteident, name);#else reply(530, "User %s unknown.", name); syslog(LOG_NOTICE, "FTP LOGIN REFUSED (ftp not in /etc/passwd) FROM %s, %s", remoteident, name);#endif } return;#endif }#ifdef ANON_ONLY/* H* fix: define the above to completely DISABLE logins by real users, despite ftpusers, shells, or any of that rot. You can always hang your "real" server off some other port, and access-control it. */ else { /* "ftp" or "anon" -- MARK your conditionals, okay?! */#ifndef HELP_CRACKERS DenyLoginAfterPassword = 1; syslog(LOG_NOTICE, "FTP LOGIN REFUSED (not anonymous) FROM %s, %s", remoteident, name); reply(331, "Password required for %s.", name);#else reply(530, "User %s unknown.", name); syslog(LOG_NOTICE, "FTP LOGIN REFUSED (not anonymous) FROM %s, %s", remoteident, name);#endif return; }/* fall here if username okay in any case */#endif /* ANON_ONLY */#if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER) if (!virtual_mode && defaultserver_deny(name) && !defaultserver_allow(name)) {#ifndef HELP_CRACKERS DenyLoginAfterPassword = 1; syslog(LOG_NOTICE, "FTP LOGIN REFUSED (ftp denied on default server) FROM %s, %s", remoteident, name);#else reply(530, "User %s access denied.", name); syslog(LOG_NOTICE, "FTP LOGIN REFUSED (ftp denied on default server) FROM %s, %s", remoteident, name); return;#endif }#endif if ((pw = sgetpwnam(name)) != NULL) { if ((denieduid(pw->pw_uid) && !alloweduid(pw->pw_uid)) || (deniedgid(pw->pw_gid) && !allowedgid(pw->pw_gid))) {#ifndef HELP_CRACKERS DenyLoginAfterPassword = 1; syslog(LOG_NOTICE, "FTP LOGIN REFUSED (username in denied-uid) FROM %s, %s", remoteident, name); reply(331, "Password required for %s.", name);#else reply(530, "User %s access denied.", name); syslog(LOG_NOTICE, "FTP LOGIN REFUSED (username in denied-uid) FROM %s, %s", remoteident, name);#endif return; }#if !defined(USE_PAM) || (defined(USE_PAM) && defined(OTHER_PASSWD)) /* PAM should be doing these checks, not ftpd */#ifdef USE_PAM if(!use_pam) {#endif if ((shell = pw->pw_shell) == NULL || *shell == 0) shell = _PATH_BSHELL; while ((cp = getusershell()) != NULL) if (strcmp(cp, shell) == 0) break; endusershell(); if (cp == NULL || checkuser(name)) {#ifndef HELP_CRACKERS DenyLoginAfterPassword = 1; if (cp == NULL) syslog(LOG_NOTICE, "FTP LOGIN REFUSED (shell not in /etc/shells) FROM %s, %s", remoteident, name); else syslog(LOG_NOTICE, "FTP LOGIN REFUSED (username in %s) FROM %s, %s", _PATH_FTPUSERS, remoteident, name); reply(331, "Password required for %s.", name);#else reply(530, "User %s access denied.", name); if (cp == NULL) syslog(LOG_NOTICE, "FTP LOGIN REFUSED (shell not in /etc/shells) FROM %s, %s", remoteident, name); else syslog(LOG_NOTICE, "FTP LOGIN REFUSED (username in %s) FROM %s, %s", _PATH_FTPUSERS, remoteident, name);#endif /* HELP_CRACKERS */ pw = (struct passwd *) NULL; return; }#ifdef USE_PAM } /* if(!use_pam) */#endif#endif /* !USE_PAM || (USE_PAM && OTHER_PASSWD) */ /* if user is a member of any of the guestgroups, cause a chroot() */ /* after they log in successfully */ if (use_accessfile) { /* see above. _H */ guest = acl_guestgroup(pw); if (guest && acl_realgroup(pw)) guest = 0; } } if (access_ok(530) < 1) {#ifndef HELP_CRACKERS DenyLoginAfterPassword = 1; syslog(LOG_NOTICE, "FTP LOGIN REFUSED (access denied) FROM %s, %s", remoteident, name); reply(331, "Password required for %s.", name);#else reply(530, "User %s access denied.", name); syslog(LOG_NOTICE, "FTP LOGIN REFUSED (access denied) FROM %s, %s", remoteident, name);#endif return; } else if (use_accessfile) /* see above. _H */ acl_setfunctions();#ifdef BSD_AUTH if ((cp = start_auth(auth, name, pw)) != NULL) { char *s; for (;;) { s = strsep(&cp, "\n"); if (cp == NULL || *cp == '\0') break; lreply(331, "%s", s); } reply(331, "%s", s); } else {#endif#ifdef SKEY#ifndef __NetBSD__#ifdef SKEY_NAME /* this is the old way, but freebsd uses it */ pwok = skeyaccess(name, NULL, remotehost, remoteaddr);#else /* this is the new way */ pwok = skeyaccess(pw, NULL, remotehost, remoteaddr);#endif reply(331, "%s", skey_challenge(name, pw, pwok));#else if (skey_haskey(name) == 0) { char *myskey; myskey = skey_keyinfo(name); reply(331, "Password [%s] required for %s.", myskey ? myskey : "error getting challenge", name); } else reply(331, "Password required for %s.", name);#endif#else#ifdef OPIE { char prompt[OPIE_CHALLENGE_MAX + 1]; opiechallenge(&opiestate, name, prompt); if (askpasswd == -1) { syslog(LOG_WARNING, "Invalid FTP user name %s attempted from %s", name, remotehost); pwok = 0; } else pwok = af_pwok && opiealways(pw->pw_dir); reply(331, "Response to %s %s for %s.", prompt, pwok ? "requested" : "required", name); }#else reply(331, "Password required for %s.", name);#endif#endif#ifdef BSD_AUTH }#endif askpasswd = 1; /* Delay before reading passwd after first failed attempt to slow down * passwd-guessing programs. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -