1623ec8b0SRandy Fishel /*
2623ec8b0SRandy Fishel * CDDL HEADER START
3623ec8b0SRandy Fishel *
4623ec8b0SRandy Fishel * The contents of this file are subject to the terms of the
5623ec8b0SRandy Fishel * Common Development and Distribution License (the "License").
6623ec8b0SRandy Fishel * You may not use this file except in compliance with the License.
7623ec8b0SRandy Fishel *
8623ec8b0SRandy Fishel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9623ec8b0SRandy Fishel * or http://www.opensolaris.org/os/licensing.
10623ec8b0SRandy Fishel * See the License for the specific language governing permissions
11623ec8b0SRandy Fishel * and limitations under the License.
12623ec8b0SRandy Fishel *
13623ec8b0SRandy Fishel * When distributing Covered Code, include this CDDL HEADER in each
14623ec8b0SRandy Fishel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15623ec8b0SRandy Fishel * If applicable, add the following below this CDDL HEADER, with the
16623ec8b0SRandy Fishel * fields enclosed by brackets "[]" replaced with your own identifying
17623ec8b0SRandy Fishel * information: Portions Copyright [yyyy] [name of copyright owner]
18623ec8b0SRandy Fishel *
19623ec8b0SRandy Fishel * CDDL HEADER END
20623ec8b0SRandy Fishel */
21623ec8b0SRandy Fishel /*
22623ec8b0SRandy Fishel * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23623ec8b0SRandy Fishel * Use is subject to license terms.
24623ec8b0SRandy Fishel */
25623ec8b0SRandy Fishel
26623ec8b0SRandy Fishel /*
27623ec8b0SRandy Fishel * This file has all of the PAM related code for sys-suspend. It is
28623ec8b0SRandy Fishel * part of it's own file, as these could be part of some bigger item
29623ec8b0SRandy Fishel * that can handle generic PAM facilities (certainly the getinput()
30623ec8b0SRandy Fishel * function could be in a common library). However, as that does not
31623ec8b0SRandy Fishel * yet exist, we replicate it here so we can get the job done.
32623ec8b0SRandy Fishel */
33623ec8b0SRandy Fishel
34623ec8b0SRandy Fishel #define __EXTENSIONS__ /* to expose flockfile and friends in stdio.h */
35623ec8b0SRandy Fishel #include <errno.h>
36623ec8b0SRandy Fishel #include <libgen.h>
37623ec8b0SRandy Fishel #include <malloc.h>
38623ec8b0SRandy Fishel #include <signal.h>
39623ec8b0SRandy Fishel #include <stdio.h>
40623ec8b0SRandy Fishel #include <stdlib.h>
41623ec8b0SRandy Fishel #include <strings.h>
42623ec8b0SRandy Fishel #include <stropts.h>
43623ec8b0SRandy Fishel #include <unistd.h>
44623ec8b0SRandy Fishel #include <termio.h>
45623ec8b0SRandy Fishel
46623ec8b0SRandy Fishel #include <security/pam_appl.h>
47623ec8b0SRandy Fishel
48623ec8b0SRandy Fishel static int ctl_c; /* was the conversation interrupted? */
49623ec8b0SRandy Fishel
50623ec8b0SRandy Fishel /* ARGSUSED 1 */
51623ec8b0SRandy Fishel static void
interrupt(int x)52623ec8b0SRandy Fishel interrupt(int x)
53623ec8b0SRandy Fishel {
54623ec8b0SRandy Fishel ctl_c = 1;
55623ec8b0SRandy Fishel }
56623ec8b0SRandy Fishel
57623ec8b0SRandy Fishel /*
58623ec8b0SRandy Fishel * getinput -- read user input from stdin abort on ^C
59623ec8b0SRandy Fishel *
60623ec8b0SRandy Fishel * Entry noecho == TRUE, don't echo input.
61623ec8b0SRandy Fishel *
62623ec8b0SRandy Fishel * Exit User's input.
63623ec8b0SRandy Fishel * If interrupted, send SIGINT to caller for processing.
64623ec8b0SRandy Fishel */
65623ec8b0SRandy Fishel static char *
getinput(int noecho)66623ec8b0SRandy Fishel getinput(int noecho)
67623ec8b0SRandy Fishel {
68623ec8b0SRandy Fishel struct termio tty;
69*5009f788SIgor Kozhukhov unsigned short tty_flags = 0;
70623ec8b0SRandy Fishel char input[PAM_MAX_RESP_SIZE + 1];
71623ec8b0SRandy Fishel int c;
72623ec8b0SRandy Fishel int i = 0;
73623ec8b0SRandy Fishel void (*sig)(int);
74623ec8b0SRandy Fishel
75623ec8b0SRandy Fishel ctl_c = 0;
76623ec8b0SRandy Fishel sig = signal(SIGINT, interrupt);
77623ec8b0SRandy Fishel if (noecho) {
78623ec8b0SRandy Fishel (void) ioctl(fileno(stdin), TCGETA, &tty);
79623ec8b0SRandy Fishel tty_flags = tty.c_lflag;
80623ec8b0SRandy Fishel tty.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
81623ec8b0SRandy Fishel (void) ioctl(fileno(stdin), TCSETAF, &tty);
82623ec8b0SRandy Fishel }
83623ec8b0SRandy Fishel /* go to end, but don't overflow PAM_MAX_RESP_SIZE */
84623ec8b0SRandy Fishel flockfile(stdin);
85623ec8b0SRandy Fishel while (ctl_c == 0 &&
86623ec8b0SRandy Fishel (c = getchar_unlocked()) != '\n' &&
87623ec8b0SRandy Fishel c != '\r' &&
88623ec8b0SRandy Fishel c != EOF) {
89623ec8b0SRandy Fishel if (i < PAM_MAX_RESP_SIZE) {
90623ec8b0SRandy Fishel input[i++] = (char)c;
91623ec8b0SRandy Fishel }
92623ec8b0SRandy Fishel }
93623ec8b0SRandy Fishel funlockfile(stdin);
94623ec8b0SRandy Fishel input[i] = '\0';
95623ec8b0SRandy Fishel if (noecho) {
96623ec8b0SRandy Fishel tty.c_lflag = tty_flags;
97623ec8b0SRandy Fishel (void) ioctl(fileno(stdin), TCSETAW, &tty);
98623ec8b0SRandy Fishel (void) fputc('\n', stdout);
99623ec8b0SRandy Fishel }
100623ec8b0SRandy Fishel (void) signal(SIGINT, sig);
101623ec8b0SRandy Fishel if (ctl_c == 1)
102623ec8b0SRandy Fishel (void) kill(getpid(), SIGINT);
103623ec8b0SRandy Fishel
104623ec8b0SRandy Fishel return (strdup(input));
105623ec8b0SRandy Fishel }
106623ec8b0SRandy Fishel
107623ec8b0SRandy Fishel /*
108623ec8b0SRandy Fishel * Service modules don't clean up responses if an error is returned.
109623ec8b0SRandy Fishel * Free responses here.
110623ec8b0SRandy Fishel */
111623ec8b0SRandy Fishel static void
free_resp(int num_msg,struct pam_response * pr)112623ec8b0SRandy Fishel free_resp(int num_msg, struct pam_response *pr)
113623ec8b0SRandy Fishel {
114623ec8b0SRandy Fishel int i;
115623ec8b0SRandy Fishel struct pam_response *r = pr;
116623ec8b0SRandy Fishel
117623ec8b0SRandy Fishel if (pr == NULL)
118623ec8b0SRandy Fishel return;
119623ec8b0SRandy Fishel
120623ec8b0SRandy Fishel for (i = 0; i < num_msg; i++, r++) {
121623ec8b0SRandy Fishel
122623ec8b0SRandy Fishel if (r->resp) {
123623ec8b0SRandy Fishel /* clear before freeing -- may be a password */
124623ec8b0SRandy Fishel bzero(r->resp, strlen(r->resp));
125623ec8b0SRandy Fishel free(r->resp);
126623ec8b0SRandy Fishel r->resp = NULL;
127623ec8b0SRandy Fishel }
128623ec8b0SRandy Fishel }
129623ec8b0SRandy Fishel free(pr);
130623ec8b0SRandy Fishel }
131623ec8b0SRandy Fishel
132623ec8b0SRandy Fishel /* ARGSUSED */
133623ec8b0SRandy Fishel int
pam_tty_conv(int num_msg,struct pam_message ** mess,struct pam_response ** resp,void * my_data)134623ec8b0SRandy Fishel pam_tty_conv(int num_msg, struct pam_message **mess,
135623ec8b0SRandy Fishel struct pam_response **resp, void *my_data)
136623ec8b0SRandy Fishel {
137623ec8b0SRandy Fishel struct pam_message *m = *mess;
138623ec8b0SRandy Fishel struct pam_response *r = calloc(num_msg, sizeof (struct pam_response));
139623ec8b0SRandy Fishel int i;
140623ec8b0SRandy Fishel
141623ec8b0SRandy Fishel if (num_msg >= PAM_MAX_NUM_MSG) {
142623ec8b0SRandy Fishel (void) fprintf(stderr, "too many messages %d >= %d\n",
143623ec8b0SRandy Fishel num_msg, PAM_MAX_NUM_MSG);
144623ec8b0SRandy Fishel free(r);
145623ec8b0SRandy Fishel *resp = NULL;
146623ec8b0SRandy Fishel return (PAM_CONV_ERR);
147623ec8b0SRandy Fishel }
148623ec8b0SRandy Fishel
149623ec8b0SRandy Fishel /* Talk it out */
150623ec8b0SRandy Fishel *resp = r;
151623ec8b0SRandy Fishel for (i = 0; i < num_msg; i++) {
152623ec8b0SRandy Fishel int echo_off;
153623ec8b0SRandy Fishel
154623ec8b0SRandy Fishel /* bad message from service module */
155623ec8b0SRandy Fishel if (m->msg == NULL) {
156623ec8b0SRandy Fishel (void) fprintf(stderr, "message[%d]: %d/NULL\n",
157623ec8b0SRandy Fishel i, m->msg_style);
158623ec8b0SRandy Fishel goto err;
159623ec8b0SRandy Fishel }
160623ec8b0SRandy Fishel
161623ec8b0SRandy Fishel /*
162623ec8b0SRandy Fishel * fix up final newline:
163623ec8b0SRandy Fishel * removed for prompts
164623ec8b0SRandy Fishel * added back for messages
165623ec8b0SRandy Fishel */
166623ec8b0SRandy Fishel if (m->msg[strlen(m->msg)] == '\n')
167623ec8b0SRandy Fishel m->msg[strlen(m->msg)] = '\0';
168623ec8b0SRandy Fishel
169623ec8b0SRandy Fishel r->resp = NULL;
170623ec8b0SRandy Fishel r->resp_retcode = 0;
171623ec8b0SRandy Fishel echo_off = 0;
172623ec8b0SRandy Fishel switch (m->msg_style) {
173623ec8b0SRandy Fishel
174623ec8b0SRandy Fishel case PAM_PROMPT_ECHO_OFF:
175623ec8b0SRandy Fishel echo_off = 1;
176623ec8b0SRandy Fishel /*FALLTHROUGH*/
177623ec8b0SRandy Fishel
178623ec8b0SRandy Fishel case PAM_PROMPT_ECHO_ON:
179623ec8b0SRandy Fishel (void) fputs(m->msg, stdout);
180623ec8b0SRandy Fishel
181623ec8b0SRandy Fishel r->resp = getinput(echo_off);
182623ec8b0SRandy Fishel break;
183623ec8b0SRandy Fishel
184623ec8b0SRandy Fishel case PAM_ERROR_MSG:
185623ec8b0SRandy Fishel (void) fputs(m->msg, stderr);
186623ec8b0SRandy Fishel (void) fputc('\n', stderr);
187623ec8b0SRandy Fishel break;
188623ec8b0SRandy Fishel
189623ec8b0SRandy Fishel case PAM_TEXT_INFO:
190623ec8b0SRandy Fishel (void) fputs(m->msg, stdout);
191623ec8b0SRandy Fishel (void) fputc('\n', stdout);
192623ec8b0SRandy Fishel break;
193623ec8b0SRandy Fishel
194623ec8b0SRandy Fishel default:
195623ec8b0SRandy Fishel (void) fprintf(stderr, "message[%d]: unknown type "
196623ec8b0SRandy Fishel "%d/val=\"%s\"\n",
197623ec8b0SRandy Fishel i, m->msg_style, m->msg);
198623ec8b0SRandy Fishel /* error, service module won't clean up */
199623ec8b0SRandy Fishel goto err;
200623ec8b0SRandy Fishel }
201623ec8b0SRandy Fishel if (errno == EINTR)
202623ec8b0SRandy Fishel goto err;
203623ec8b0SRandy Fishel
204623ec8b0SRandy Fishel /* next message/response */
205623ec8b0SRandy Fishel m++;
206623ec8b0SRandy Fishel r++;
207623ec8b0SRandy Fishel }
208623ec8b0SRandy Fishel return (PAM_SUCCESS);
209623ec8b0SRandy Fishel
210623ec8b0SRandy Fishel err:
211623ec8b0SRandy Fishel free_resp(i, r);
212623ec8b0SRandy Fishel *resp = NULL;
213623ec8b0SRandy Fishel return (PAM_CONV_ERR);
214623ec8b0SRandy Fishel }
215