summaryrefslogtreecommitdiff
path: root/Linux-PAM/modules/pam_issue/pam_issue.c
diff options
context:
space:
mode:
Diffstat (limited to 'Linux-PAM/modules/pam_issue/pam_issue.c')
-rw-r--r--Linux-PAM/modules/pam_issue/pam_issue.c310
1 files changed, 310 insertions, 0 deletions
diff --git a/Linux-PAM/modules/pam_issue/pam_issue.c b/Linux-PAM/modules/pam_issue/pam_issue.c
new file mode 100644
index 00000000..7a8a24d5
--- /dev/null
+++ b/Linux-PAM/modules/pam_issue/pam_issue.c
@@ -0,0 +1,310 @@
+/* pam_issue module - a simple /etc/issue parser to set PAM_USER_PROMPT
+ *
+ * Copyright 1999 by Ben Collins <bcollins@debian.org>
+ *
+ * Needs to be called before any other auth modules so we can setup the
+ * user prompt before it's first used. Allows one argument option, which
+ * is the full path to a file to be used for issue (uses /etc/issue as a
+ * default) such as "issue=/etc/issue.telnet".
+ *
+ * We can also parse escapes within the the issue file (enabled by
+ * default, but can be disabled with the "noesc" option). It's the exact
+ * same parsing as util-linux's agetty program performs.
+ *
+ * Released under the GNU LGPL version 2 or later
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/utsname.h>
+#include <utmp.h>
+#include <time.h>
+#include <syslog.h>
+
+#define PAM_SM_AUTH
+
+#include <security/_pam_macros.h>
+#include <security/pam_modules.h>
+#include <security/pam_ext.h>
+
+static int _user_prompt_set = 0;
+
+static int read_issue_raw(pam_handle_t *pamh, FILE *fp, char **prompt);
+static int read_issue_quoted(pam_handle_t *pamh, FILE *fp, char **prompt);
+
+/* --- authentication management functions (only) --- */
+
+PAM_EXTERN int
+pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED,
+ int argc, const char **argv)
+{
+ int retval = PAM_SERVICE_ERR;
+ FILE *fp;
+ const char *issue_file = NULL;
+ int parse_esc = 1;
+ const void *item = NULL;
+ const char *cur_prompt;
+ char *issue_prompt = NULL;
+
+ /* If we've already set the prompt, don't set it again */
+ if(_user_prompt_set)
+ return PAM_IGNORE;
+
+ /* We set this here so if we fail below, we wont get further
+ than this next time around (only one real failure) */
+ _user_prompt_set = 1;
+
+ for ( ; argc-- > 0 ; ++argv ) {
+ if (!strncmp(*argv,"issue=",6)) {
+ issue_file = 6 + *argv;
+ D(("set issue_file to: %s", issue_file));
+ } else if (!strcmp(*argv,"noesc")) {
+ parse_esc = 0;
+ D(("turning off escape parsing by request"));
+ } else
+ D(("unknown option passed: %s", *argv));
+ }
+
+ if (issue_file == NULL)
+ issue_file = "/etc/issue";
+
+ if ((fp = fopen(issue_file, "r")) == NULL) {
+ pam_syslog(pamh, LOG_ERR, "error opening %s: %m", issue_file);
+ return PAM_SERVICE_ERR;
+ }
+
+ if ((retval = pam_get_item(pamh, PAM_USER_PROMPT, &item)) != PAM_SUCCESS) {
+ fclose(fp);
+ return retval;
+ }
+
+ cur_prompt = item;
+ if (cur_prompt == NULL)
+ cur_prompt = "";
+
+ if (parse_esc)
+ retval = read_issue_quoted(pamh, fp, &issue_prompt);
+ else
+ retval = read_issue_raw(pamh, fp, &issue_prompt);
+
+ fclose(fp);
+
+ if (retval != PAM_SUCCESS)
+ goto out;
+
+ {
+ size_t size = strlen(issue_prompt) + strlen(cur_prompt) + 1;
+ char *new_prompt = realloc(issue_prompt, size);
+
+ if (new_prompt == NULL) {
+ pam_syslog(pamh, LOG_ERR, "out of memory");
+ retval = PAM_BUF_ERR;
+ goto out;
+ }
+ issue_prompt = new_prompt;
+ }
+
+ strcat(issue_prompt, cur_prompt);
+ retval = pam_set_item(pamh, PAM_USER_PROMPT,
+ (const void *) issue_prompt);
+ out:
+ _pam_drop(issue_prompt);
+ return (retval == PAM_SUCCESS) ? PAM_IGNORE : retval;
+}
+
+PAM_EXTERN int
+pam_sm_setcred (pam_handle_t *pamh UNUSED, int flags UNUSED,
+ int argc UNUSED, const char **argv UNUSED)
+{
+ return PAM_IGNORE;
+}
+
+static int
+read_issue_raw(pam_handle_t *pamh, FILE *fp, char **prompt)
+{
+ char *issue;
+ struct stat st;
+
+ *prompt = NULL;
+
+ if (fstat(fileno(fp), &st) < 0) {
+ pam_syslog(pamh, LOG_ERR, "stat error: %m");
+ return PAM_SERVICE_ERR;
+ }
+
+ if ((issue = malloc(st.st_size + 1)) == NULL) {
+ pam_syslog(pamh, LOG_ERR, "out of memory");
+ return PAM_BUF_ERR;
+ }
+
+ if (fread(issue, 1, st.st_size, fp) != st.st_size) {
+ pam_syslog(pamh, LOG_ERR, "read error: %m");
+ _pam_drop(issue);
+ return PAM_SERVICE_ERR;
+ }
+
+ issue[st.st_size] = '\0';
+ *prompt = issue;
+ return PAM_SUCCESS;
+}
+
+static int
+read_issue_quoted(pam_handle_t *pamh, FILE *fp, char **prompt)
+{
+ int c;
+ size_t size = 1024;
+ char *issue;
+ struct utsname uts;
+
+ *prompt = NULL;
+
+ if ((issue = malloc(size)) == NULL) {
+ pam_syslog(pamh, LOG_ERR, "out of memory");
+ return PAM_BUF_ERR;
+ }
+
+ issue[0] = '\0';
+ (void) uname(&uts);
+
+ while ((c = getc(fp)) != EOF) {
+ char buf[1024];
+
+ buf[0] = '\0';
+ if (c == '\\') {
+ if ((c = getc(fp)) == EOF)
+ break;
+ switch (c) {
+ case 's':
+ strncat(buf, uts.sysname, sizeof(buf) - 1);
+ break;
+ case 'n':
+ strncat(buf, uts.nodename, sizeof(buf) - 1);
+ break;
+ case 'r':
+ strncat(buf, uts.release, sizeof(buf) - 1);
+ break;
+ case 'v':
+ strncat(buf, uts.version, sizeof(buf) - 1);
+ break;
+ case 'm':
+ strncat(buf, uts.machine, sizeof(buf) - 1);
+ break;
+ case 'o':
+ {
+ char domainname[256];
+
+ if (getdomainname(domainname, sizeof(domainname)) >= 0) {
+ domainname[sizeof(domainname)-1] = '\0';
+ strncat(buf, domainname, sizeof(buf) - 1);
+ }
+ }
+ break;
+ case 'd':
+ case 't':
+ {
+ const char *weekday[] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu",
+ "Fri", "Sat" };
+ const char *month[] = {
+ "Jan", "Feb", "Mar", "Apr", "May",
+ "Jun", "Jul", "Aug", "Sep", "Oct",
+ "Nov", "Dec" };
+ time_t now;
+ struct tm *tm;
+
+ (void) time (&now);
+ tm = localtime(&now);
+
+ if (c == 'd')
+ snprintf (buf, sizeof buf, "%s %s %d %d",
+ weekday[tm->tm_wday], month[tm->tm_mon],
+ tm->tm_mday, tm->tm_year + 1900);
+ else
+ snprintf (buf, sizeof buf, "%02d:%02d:%02d",
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ }
+ break;
+ case 'l':
+ {
+ char *ttyn = ttyname(1);
+ if (ttyn) {
+ if (!strncmp(ttyn, "/dev/", 5))
+ ttyn += 5;
+ strncat(buf, ttyn, sizeof(buf) - 1);
+ }
+ }
+ break;
+ case 'u':
+ case 'U':
+ {
+ unsigned int users = 0;
+ struct utmp *ut;
+ setutent();
+ while ((ut = getutent())) {
+ if (ut->ut_type == USER_PROCESS)
+ ++users;
+ }
+ endutent();
+ if (c == 'U')
+ snprintf (buf, sizeof buf, "%u %s", users,
+ (users == 1) ? "user" : "users");
+ else
+ snprintf (buf, sizeof buf, "%u", users);
+ break;
+ }
+ default:
+ buf[0] = c; buf[1] = '\0';
+ }
+ } else {
+ buf[0] = c; buf[1] = '\0';
+ }
+
+ if ((strlen(issue) + strlen(buf)) + 1 > size) {
+ char *new_issue;
+
+ size += strlen(buf) + 1;
+ new_issue = (char *) realloc (issue, size);
+ if (new_issue == NULL) {
+ _pam_drop(issue);
+ return PAM_BUF_ERR;
+ }
+ issue = new_issue;
+ strcat(issue, buf);
+ }
+ }
+
+ if (ferror(fp)) {
+ pam_syslog(pamh, LOG_ERR, "read error: %m");
+ _pam_drop(issue);
+ return PAM_SERVICE_ERR;
+ }
+
+ *prompt = issue;
+ return PAM_SUCCESS;
+}
+
+#ifdef PAM_STATIC
+
+/* static module data */
+
+struct pam_module _pam_issue_modstruct = {
+ "pam_issue",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+#endif
+
+/* end of module definition */