Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / libpam / modules / pam_issue / pam_issue.c
1 /* pam_issue module - a simple /etc/issue parser to set PAM_USER_PROMPT
2  *
3  * Copyright 1999 by Ben Collins <bcollins@debian.org>
4  *
5  * Needs to be called before any other auth modules so we can setup the
6  * user prompt before it's first used. Allows one argument option, which
7  * is the full path to a file to be used for issue (uses /etc/issue as a
8  * default) such as "issue=/etc/issue.telnet".
9  *
10  * We can also parse escapes within the the issue file (enabled by
11  * default, but can be disabled with the "noesc" option). It's the exact
12  * same parsing as util-linux's agetty program performs.
13  *
14  * Released under the GNU LGPL version 2 or later
15  * $FreeBSD: src/contrib/libpam/modules/pam_issue/pam_issue.c,v 1.1.1.1.2.2 2001/06/11 15:28:18 markm Exp $
16  */
17
18 #define _GNU_SOURCE
19 #define _BSD_SOURCE
20
21 #include <string.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <time.h>
27 #include <fcntl.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <sys/utsname.h>
31 #include <utmp.h>
32 #include <malloc.h>
33
34 #include <security/_pam_macros.h>
35
36 #define PAM_SM_AUTH
37
38 #include <security/pam_modules.h>
39
40 static int _user_prompt_set = 0;
41
42 char *do_prompt (FILE *);
43
44 /* --- authentication management functions (only) --- */
45
46 PAM_EXTERN
47 int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
48                         const char **argv)
49 {
50     int retval = PAM_SUCCESS;
51     FILE *fd;
52     int parse_esc = 1;
53     char *prompt_tmp = NULL, *cur_prompt = NULL;
54     struct stat st;
55     char *issue_file = NULL;
56
57    /* If we've already set the prompt, don't set it again */
58     if(_user_prompt_set)
59         return PAM_IGNORE;
60     else
61        /* we set this here so if we fail below, we wont get further
62           than this next time around (only one real failure) */
63         _user_prompt_set = 1;
64
65     for ( ; argc-- > 0 ; ++argv ) {
66         if (!strncmp(*argv,"issue=",6)) {
67             issue_file = (char *) strdup(6+*argv);
68             if (issue_file != NULL) {
69                 D(("set issue_file to: %s", issue_file));
70             } else {
71                 D(("failed to strdup issue_file - ignored"));
72                 return PAM_IGNORE;
73             }
74         } else if (!strcmp(*argv,"noesc")) {
75             parse_esc = 0;
76             D(("turning off escape parsing by request"));
77         } else
78             D(("unknown option passed: %s", *argv));
79     }
80
81     if (issue_file == NULL)
82         issue_file = strdup("/etc/issue");
83
84     if ((fd = fopen(issue_file, "r")) != NULL) {
85         int tot_size = 0;
86
87         if (stat(issue_file, &st) < 0)
88             return PAM_IGNORE;
89
90         retval = pam_get_item(pamh, PAM_USER_PROMPT, (const void **) &cur_prompt);
91         if (retval != PAM_SUCCESS)
92             return PAM_IGNORE;
93
94        /* first read in the issue file */
95
96         if (parse_esc)
97             prompt_tmp = do_prompt(fd);
98         else {
99             int count = 0;
100             prompt_tmp = malloc(st.st_size + 1);
101             if (prompt_tmp == NULL) return PAM_IGNORE;
102             memset (prompt_tmp, '\0', st.st_size + 1);
103             count = fread(prompt_tmp, sizeof(char *), st.st_size, fd);
104             prompt_tmp[st.st_size] = '\0';
105         }
106
107         fclose(fd);
108
109         tot_size = strlen(prompt_tmp) + strlen(cur_prompt) + 1;
110
111        /*
112         * alloc some extra space for the original prompt
113         * and postpend it to the buffer
114         */
115         prompt_tmp = realloc(prompt_tmp, tot_size);
116         strcpy(prompt_tmp+strlen(prompt_tmp), cur_prompt);
117
118         prompt_tmp[tot_size] = '\0';
119
120         retval = pam_set_item(pamh, PAM_USER_PROMPT, (const char *) prompt_tmp);
121
122         free(issue_file);
123         free(prompt_tmp);
124     } else {
125         D(("could not open issue_file: %s", issue_file));
126         return PAM_IGNORE;
127     }
128
129     return retval;
130 }
131
132 PAM_EXTERN
133 int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
134                    const char **argv)
135 {
136      return PAM_IGNORE;
137 }
138
139 char *do_prompt(FILE *fd)
140 {
141     int c, size = 1024;
142     char *issue = (char *)malloc(size);
143     char buf[1024];
144     struct utsname uts;
145
146     if (issue == NULL || fd == NULL)
147         return NULL;
148
149     issue[0] = '\0'; /* zero this, for strcat to work on first buf */
150     (void) uname(&uts);
151
152     while ((c = getc(fd)) != EOF) {
153         if (c == '\\') {
154             c = getc(fd);
155             switch (c) {
156               case 's':
157                 snprintf (buf, 1024, "%s", uts.sysname);
158                 break;
159               case 'n':
160                 snprintf (buf, 1024, "%s", uts.nodename);
161                 break;
162               case 'r':
163                 snprintf (buf, 1024, "%s", uts.release);
164                 break;
165               case 'v':
166                 snprintf (buf, 1024, "%s", uts.version);
167                 break;
168               case 'm':
169                 snprintf (buf, 1024, "%s", uts.machine);
170                 break;
171               case 'o':
172                 {
173                     char domainname[256];
174
175                     getdomainname(domainname, sizeof(domainname));
176                     domainname[sizeof(domainname)-1] = '\0';
177                     snprintf (buf, 1024, "%s", domainname);
178                 }
179                 break;
180
181               case 'd':
182               case 't':
183                 {
184                     const char *weekday[] = {
185                         "Sun", "Mon", "Tue", "Wed", "Thu",
186                         "Fri", "Sat" };
187                     const char *month[] = {
188                         "Jan", "Feb", "Mar", "Apr", "May",
189                         "Jun", "Jul", "Aug", "Sep", "Oct",
190                         "Nov", "Dec" };
191                     time_t now;
192                     struct tm *tm;
193
194                     (void) time (&now);
195                     tm = localtime(&now);
196
197                     if (c == 'd')
198                         snprintf (buf, 1024, "%s %s %d  %d",
199                                 weekday[tm->tm_wday], month[tm->tm_mon],
200                                 tm->tm_mday, 
201                                 tm->tm_year + 1900);
202                     else
203                         snprintf (buf, 1024, "%02d:%02d:%02d",
204                                 tm->tm_hour, tm->tm_min, tm->tm_sec);
205                 }
206                 break;
207               case 'l':
208                 {
209                     char *ttyn = ttyname(1);
210                     if (!strncmp(ttyn, "/dev/", 5))
211                         ttyn += 5;
212                     snprintf (buf, 1024, "%s", ttyn);
213                 }
214                 break;
215               case 'u':
216               case 'U':
217                 {
218                     int users = 0;
219                     struct utmp *ut;
220                     setutent();
221                     while ((ut = getutent()))
222                         if (ut->ut_type == USER_PROCESS)
223                         users++;
224                     endutent();
225                     printf ("%d ", users);
226                     if (c == 'U')
227                         snprintf (buf, 1024, "%s", (users == 1) ?
228                                 " user" : " users");
229                     break;
230                 }
231               default:
232                 buf[0] = c; buf[1] = '\0';
233             }
234             if ((strlen(issue) + strlen(buf)) < size + 1) {
235                 size += strlen(buf) + 1;
236                 issue = (char *) realloc (issue, size);
237             }
238             strcat(issue, buf);
239         } else {
240             buf[0] = c; buf[1] = '\0';
241             if ((strlen(issue) + strlen(buf)) < size + 1) {
242                 size += strlen(buf) + 1;
243                 issue = (char *) realloc (issue, size);
244             }
245             strcat(issue, buf);
246         }
247     }
248     return issue;
249 }
250
251 #ifdef PAM_STATIC
252
253 /* static module data */
254
255 struct pam_module _pam_issue_modstruct = {
256      "pam_issue",
257      pam_sm_authenticate,
258      pam_sm_setcred,
259      NULL,
260      NULL,
261      NULL,
262      NULL,
263 };
264
265 #endif
266
267 /* end of module definition */