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