/* * Output the /etc/motd file. * * It determines the name of a login announcement file and outputs it to the * user's terminal at login time. The MOTD_FILE configuration option is a * colon-delimited list of filenames. An empty MOTD_FILE option disables * message-of-the-day printing completely. */ static void motd(void) { char *motdlist, *motdfile; const char *mb; mb = getlogindefs_str("MOTD_FILE", _PATH_MOTDFILE); if (!mb || !*mb) return; motdlist = xstrdup(mb); for (motdfile = strtok(motdlist, ":"); motdfile; motdfile = strtok(NULL, ":")) { struct stat st; int fd; fd = open(motdfile, O_RDONLY, 0); if (fd < 0) continue; if (!fstat(fd, &st) && st.st_size) sendfile(fileno(stdout), fd, NULL, st.st_size); close(fd); } free(motdlist); }
static void chown_tty(struct login_context *cxt) { const char *grname; uid_t uid = cxt->pwd->pw_uid; gid_t gid = cxt->pwd->pw_gid; grname = getlogindefs_str("TTYGROUP", TTYGRPNAME); if (grname && *grname) { struct group *gr = getgrnam(grname); if (gr) /* group by name */ gid = gr->gr_gid; else /* group by ID */ gid = (gid_t) getlogindefs_num("TTYGROUP", gid); } if (fchown(0, uid, gid)) /* tty */ chown_err(cxt->tty_name, uid, gid); if (fchmod(0, cxt->tty_mode)) chmod_err(cxt->tty_name, cxt->tty_mode); #ifdef LOGIN_CHOWN_VCS if (is_consoletty(0)) { if (chown(cxt->vcsn, uid, gid)) /* vcs */ chown_err(cxt->vcsn, uid, gid); if (chmod(cxt->vcsn, cxt->tty_mode)) chmod_err(cxt->vcsn, cxt->tty_mode); if (chown(cxt->vcsan, uid, gid)) /* vcsa */ chown_err(cxt->vcsan, uid, gid); if (chmod(cxt->vcsan, cxt->tty_mode)) chmod_err(cxt->vcsan, cxt->tty_mode); } #endif }
/* * Check per accout or global hush-login setting. * * Hushed mode is enabled: * * a) if global (e.g. /etc/hushlogins) hush file exists: * 1) for ALL ACCOUNTS if the file is empty * 2) for the current user if the username or shell are found in the file * * b) if ~/.hushlogin file exists * * The ~/.hushlogin is ignored if the global hush file exists. * * The HUSHLOGIN_FILE login.def variable overwrites the default hush filename. * * Note that shadow-utils login(1) does not support "a1)". The "a1)" is * necessary if you want to use PAM for "Last login" message. * * -- Karel Zak <*****@*****.**> (26-Aug-2011) * * * Per-account check requires some explanation: As root we may not be able to * read the directory of the user if it is on an NFS mounted filesystem. We * temporarily set our effective uid to the user-uid making sure that we keep * root privs. in the real uid. * * A portable solution would require a fork(), but we rely on Linux having the * BSD setreuid() */ static int get_hushlogin_status(struct passwd *pwd) { const char *files[] = { _PATH_HUSHLOGINS, _PATH_HUSHLOGIN, NULL }; const char *file; char buf[BUFSIZ]; int i; file = getlogindefs_str("HUSHLOGIN_FILE", NULL); if (file) { if (!*file) return 0; /* empty HUSHLOGIN_FILE defined */ files[0] = file; files[1] = NULL; } for (i = 0; files[i]; i++) { int ok = 0; file = files[i]; /* Global hush-file*/ if (*file == '/') { struct stat st; FILE *f; if (stat(file, &st) != 0) continue; /* file does not exist */ if (st.st_size == 0) return 1; /* for all accounts */ f = fopen(file, "r"); if (!f) continue; /* ignore errors... */ while (ok == 0 && fgets(buf, sizeof(buf), f)) { buf[strlen(buf) - 1] = '\0'; ok = !strcmp(buf, *buf == '/' ? pwd->pw_shell : pwd->pw_name); } fclose(f); if (ok) return 1; /* found username/shell */ return 0; /* ignore per-account files */ } /* Per-account setting */ if (strlen(pwd->pw_dir) + sizeof(file) + 2 > sizeof(buf)) continue; else { uid_t ruid = getuid(); gid_t egid = getegid(); sprintf(buf, "%s/%s", pwd->pw_dir, file); setregid(-1, pwd->pw_gid); setreuid(0, pwd->pw_uid); ok = effective_access(buf, O_RDONLY) == 0; setuid(0); /* setreuid doesn't do it alone! */ setreuid(ruid, 0); setregid(-1, egid); if (ok) return 1; /* enabled by user */ } } return 0; }