1*8940SRandy.Fishel@Sun.COM /*
2*8940SRandy.Fishel@Sun.COM * CDDL HEADER START
3*8940SRandy.Fishel@Sun.COM *
4*8940SRandy.Fishel@Sun.COM * The contents of this file are subject to the terms of the
5*8940SRandy.Fishel@Sun.COM * Common Development and Distribution License (the "License").
6*8940SRandy.Fishel@Sun.COM * You may not use this file except in compliance with the License.
7*8940SRandy.Fishel@Sun.COM *
8*8940SRandy.Fishel@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*8940SRandy.Fishel@Sun.COM * or http://www.opensolaris.org/os/licensing.
10*8940SRandy.Fishel@Sun.COM * See the License for the specific language governing permissions
11*8940SRandy.Fishel@Sun.COM * and limitations under the License.
12*8940SRandy.Fishel@Sun.COM *
13*8940SRandy.Fishel@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
14*8940SRandy.Fishel@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*8940SRandy.Fishel@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
16*8940SRandy.Fishel@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
17*8940SRandy.Fishel@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
18*8940SRandy.Fishel@Sun.COM *
19*8940SRandy.Fishel@Sun.COM * CDDL HEADER END
20*8940SRandy.Fishel@Sun.COM */
21*8940SRandy.Fishel@Sun.COM /*
22*8940SRandy.Fishel@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23*8940SRandy.Fishel@Sun.COM * Use is subject to license terms.
24*8940SRandy.Fishel@Sun.COM */
25*8940SRandy.Fishel@Sun.COM
26*8940SRandy.Fishel@Sun.COM /*
27*8940SRandy.Fishel@Sun.COM * This file has all of the PAM related code for sys-suspend. It is
28*8940SRandy.Fishel@Sun.COM * part of it's own file, as these could be part of some bigger item
29*8940SRandy.Fishel@Sun.COM * that can handle generic PAM facilities (certainly the getinput()
30*8940SRandy.Fishel@Sun.COM * function could be in a common library). However, as that does not
31*8940SRandy.Fishel@Sun.COM * yet exist, we replicate it here so we can get the job done.
32*8940SRandy.Fishel@Sun.COM */
33*8940SRandy.Fishel@Sun.COM
34*8940SRandy.Fishel@Sun.COM #define __EXTENSIONS__ /* to expose flockfile and friends in stdio.h */
35*8940SRandy.Fishel@Sun.COM #include <errno.h>
36*8940SRandy.Fishel@Sun.COM #include <libgen.h>
37*8940SRandy.Fishel@Sun.COM #include <malloc.h>
38*8940SRandy.Fishel@Sun.COM #include <signal.h>
39*8940SRandy.Fishel@Sun.COM #include <stdio.h>
40*8940SRandy.Fishel@Sun.COM #include <stdlib.h>
41*8940SRandy.Fishel@Sun.COM #include <strings.h>
42*8940SRandy.Fishel@Sun.COM #include <stropts.h>
43*8940SRandy.Fishel@Sun.COM #include <unistd.h>
44*8940SRandy.Fishel@Sun.COM #include <termio.h>
45*8940SRandy.Fishel@Sun.COM
46*8940SRandy.Fishel@Sun.COM #include <security/pam_appl.h>
47*8940SRandy.Fishel@Sun.COM
48*8940SRandy.Fishel@Sun.COM static int ctl_c; /* was the conversation interrupted? */
49*8940SRandy.Fishel@Sun.COM
50*8940SRandy.Fishel@Sun.COM /* ARGSUSED 1 */
51*8940SRandy.Fishel@Sun.COM static void
interrupt(int x)52*8940SRandy.Fishel@Sun.COM interrupt(int x)
53*8940SRandy.Fishel@Sun.COM {
54*8940SRandy.Fishel@Sun.COM ctl_c = 1;
55*8940SRandy.Fishel@Sun.COM }
56*8940SRandy.Fishel@Sun.COM
57*8940SRandy.Fishel@Sun.COM /*
58*8940SRandy.Fishel@Sun.COM * getinput -- read user input from stdin abort on ^C
59*8940SRandy.Fishel@Sun.COM *
60*8940SRandy.Fishel@Sun.COM * Entry noecho == TRUE, don't echo input.
61*8940SRandy.Fishel@Sun.COM *
62*8940SRandy.Fishel@Sun.COM * Exit User's input.
63*8940SRandy.Fishel@Sun.COM * If interrupted, send SIGINT to caller for processing.
64*8940SRandy.Fishel@Sun.COM */
65*8940SRandy.Fishel@Sun.COM static char *
getinput(int noecho)66*8940SRandy.Fishel@Sun.COM getinput(int noecho)
67*8940SRandy.Fishel@Sun.COM {
68*8940SRandy.Fishel@Sun.COM struct termio tty;
69*8940SRandy.Fishel@Sun.COM unsigned short tty_flags;
70*8940SRandy.Fishel@Sun.COM char input[PAM_MAX_RESP_SIZE + 1];
71*8940SRandy.Fishel@Sun.COM int c;
72*8940SRandy.Fishel@Sun.COM int i = 0;
73*8940SRandy.Fishel@Sun.COM void (*sig)(int);
74*8940SRandy.Fishel@Sun.COM
75*8940SRandy.Fishel@Sun.COM ctl_c = 0;
76*8940SRandy.Fishel@Sun.COM sig = signal(SIGINT, interrupt);
77*8940SRandy.Fishel@Sun.COM if (noecho) {
78*8940SRandy.Fishel@Sun.COM (void) ioctl(fileno(stdin), TCGETA, &tty);
79*8940SRandy.Fishel@Sun.COM tty_flags = tty.c_lflag;
80*8940SRandy.Fishel@Sun.COM tty.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
81*8940SRandy.Fishel@Sun.COM (void) ioctl(fileno(stdin), TCSETAF, &tty);
82*8940SRandy.Fishel@Sun.COM }
83*8940SRandy.Fishel@Sun.COM /* go to end, but don't overflow PAM_MAX_RESP_SIZE */
84*8940SRandy.Fishel@Sun.COM flockfile(stdin);
85*8940SRandy.Fishel@Sun.COM while (ctl_c == 0 &&
86*8940SRandy.Fishel@Sun.COM (c = getchar_unlocked()) != '\n' &&
87*8940SRandy.Fishel@Sun.COM c != '\r' &&
88*8940SRandy.Fishel@Sun.COM c != EOF) {
89*8940SRandy.Fishel@Sun.COM if (i < PAM_MAX_RESP_SIZE) {
90*8940SRandy.Fishel@Sun.COM input[i++] = (char)c;
91*8940SRandy.Fishel@Sun.COM }
92*8940SRandy.Fishel@Sun.COM }
93*8940SRandy.Fishel@Sun.COM funlockfile(stdin);
94*8940SRandy.Fishel@Sun.COM input[i] = '\0';
95*8940SRandy.Fishel@Sun.COM if (noecho) {
96*8940SRandy.Fishel@Sun.COM tty.c_lflag = tty_flags;
97*8940SRandy.Fishel@Sun.COM (void) ioctl(fileno(stdin), TCSETAW, &tty);
98*8940SRandy.Fishel@Sun.COM (void) fputc('\n', stdout);
99*8940SRandy.Fishel@Sun.COM }
100*8940SRandy.Fishel@Sun.COM (void) signal(SIGINT, sig);
101*8940SRandy.Fishel@Sun.COM if (ctl_c == 1)
102*8940SRandy.Fishel@Sun.COM (void) kill(getpid(), SIGINT);
103*8940SRandy.Fishel@Sun.COM
104*8940SRandy.Fishel@Sun.COM return (strdup(input));
105*8940SRandy.Fishel@Sun.COM }
106*8940SRandy.Fishel@Sun.COM
107*8940SRandy.Fishel@Sun.COM /*
108*8940SRandy.Fishel@Sun.COM * Service modules don't clean up responses if an error is returned.
109*8940SRandy.Fishel@Sun.COM * Free responses here.
110*8940SRandy.Fishel@Sun.COM */
111*8940SRandy.Fishel@Sun.COM static void
free_resp(int num_msg,struct pam_response * pr)112*8940SRandy.Fishel@Sun.COM free_resp(int num_msg, struct pam_response *pr)
113*8940SRandy.Fishel@Sun.COM {
114*8940SRandy.Fishel@Sun.COM int i;
115*8940SRandy.Fishel@Sun.COM struct pam_response *r = pr;
116*8940SRandy.Fishel@Sun.COM
117*8940SRandy.Fishel@Sun.COM if (pr == NULL)
118*8940SRandy.Fishel@Sun.COM return;
119*8940SRandy.Fishel@Sun.COM
120*8940SRandy.Fishel@Sun.COM for (i = 0; i < num_msg; i++, r++) {
121*8940SRandy.Fishel@Sun.COM
122*8940SRandy.Fishel@Sun.COM if (r->resp) {
123*8940SRandy.Fishel@Sun.COM /* clear before freeing -- may be a password */
124*8940SRandy.Fishel@Sun.COM bzero(r->resp, strlen(r->resp));
125*8940SRandy.Fishel@Sun.COM free(r->resp);
126*8940SRandy.Fishel@Sun.COM r->resp = NULL;
127*8940SRandy.Fishel@Sun.COM }
128*8940SRandy.Fishel@Sun.COM }
129*8940SRandy.Fishel@Sun.COM free(pr);
130*8940SRandy.Fishel@Sun.COM }
131*8940SRandy.Fishel@Sun.COM
132*8940SRandy.Fishel@Sun.COM /* ARGSUSED */
133*8940SRandy.Fishel@Sun.COM int
pam_tty_conv(int num_msg,struct pam_message ** mess,struct pam_response ** resp,void * my_data)134*8940SRandy.Fishel@Sun.COM pam_tty_conv(int num_msg, struct pam_message **mess,
135*8940SRandy.Fishel@Sun.COM struct pam_response **resp, void *my_data)
136*8940SRandy.Fishel@Sun.COM {
137*8940SRandy.Fishel@Sun.COM struct pam_message *m = *mess;
138*8940SRandy.Fishel@Sun.COM struct pam_response *r = calloc(num_msg, sizeof (struct pam_response));
139*8940SRandy.Fishel@Sun.COM int i;
140*8940SRandy.Fishel@Sun.COM
141*8940SRandy.Fishel@Sun.COM if (num_msg >= PAM_MAX_NUM_MSG) {
142*8940SRandy.Fishel@Sun.COM (void) fprintf(stderr, "too many messages %d >= %d\n",
143*8940SRandy.Fishel@Sun.COM num_msg, PAM_MAX_NUM_MSG);
144*8940SRandy.Fishel@Sun.COM free(r);
145*8940SRandy.Fishel@Sun.COM *resp = NULL;
146*8940SRandy.Fishel@Sun.COM return (PAM_CONV_ERR);
147*8940SRandy.Fishel@Sun.COM }
148*8940SRandy.Fishel@Sun.COM
149*8940SRandy.Fishel@Sun.COM /* Talk it out */
150*8940SRandy.Fishel@Sun.COM *resp = r;
151*8940SRandy.Fishel@Sun.COM for (i = 0; i < num_msg; i++) {
152*8940SRandy.Fishel@Sun.COM int echo_off;
153*8940SRandy.Fishel@Sun.COM
154*8940SRandy.Fishel@Sun.COM /* bad message from service module */
155*8940SRandy.Fishel@Sun.COM if (m->msg == NULL) {
156*8940SRandy.Fishel@Sun.COM (void) fprintf(stderr, "message[%d]: %d/NULL\n",
157*8940SRandy.Fishel@Sun.COM i, m->msg_style);
158*8940SRandy.Fishel@Sun.COM goto err;
159*8940SRandy.Fishel@Sun.COM }
160*8940SRandy.Fishel@Sun.COM
161*8940SRandy.Fishel@Sun.COM /*
162*8940SRandy.Fishel@Sun.COM * fix up final newline:
163*8940SRandy.Fishel@Sun.COM * removed for prompts
164*8940SRandy.Fishel@Sun.COM * added back for messages
165*8940SRandy.Fishel@Sun.COM */
166*8940SRandy.Fishel@Sun.COM if (m->msg[strlen(m->msg)] == '\n')
167*8940SRandy.Fishel@Sun.COM m->msg[strlen(m->msg)] = '\0';
168*8940SRandy.Fishel@Sun.COM
169*8940SRandy.Fishel@Sun.COM r->resp = NULL;
170*8940SRandy.Fishel@Sun.COM r->resp_retcode = 0;
171*8940SRandy.Fishel@Sun.COM echo_off = 0;
172*8940SRandy.Fishel@Sun.COM switch (m->msg_style) {
173*8940SRandy.Fishel@Sun.COM
174*8940SRandy.Fishel@Sun.COM case PAM_PROMPT_ECHO_OFF:
175*8940SRandy.Fishel@Sun.COM echo_off = 1;
176*8940SRandy.Fishel@Sun.COM /*FALLTHROUGH*/
177*8940SRandy.Fishel@Sun.COM
178*8940SRandy.Fishel@Sun.COM case PAM_PROMPT_ECHO_ON:
179*8940SRandy.Fishel@Sun.COM (void) fputs(m->msg, stdout);
180*8940SRandy.Fishel@Sun.COM
181*8940SRandy.Fishel@Sun.COM r->resp = getinput(echo_off);
182*8940SRandy.Fishel@Sun.COM break;
183*8940SRandy.Fishel@Sun.COM
184*8940SRandy.Fishel@Sun.COM case PAM_ERROR_MSG:
185*8940SRandy.Fishel@Sun.COM (void) fputs(m->msg, stderr);
186*8940SRandy.Fishel@Sun.COM (void) fputc('\n', stderr);
187*8940SRandy.Fishel@Sun.COM break;
188*8940SRandy.Fishel@Sun.COM
189*8940SRandy.Fishel@Sun.COM case PAM_TEXT_INFO:
190*8940SRandy.Fishel@Sun.COM (void) fputs(m->msg, stdout);
191*8940SRandy.Fishel@Sun.COM (void) fputc('\n', stdout);
192*8940SRandy.Fishel@Sun.COM break;
193*8940SRandy.Fishel@Sun.COM
194*8940SRandy.Fishel@Sun.COM default:
195*8940SRandy.Fishel@Sun.COM (void) fprintf(stderr, "message[%d]: unknown type "
196*8940SRandy.Fishel@Sun.COM "%d/val=\"%s\"\n",
197*8940SRandy.Fishel@Sun.COM i, m->msg_style, m->msg);
198*8940SRandy.Fishel@Sun.COM /* error, service module won't clean up */
199*8940SRandy.Fishel@Sun.COM goto err;
200*8940SRandy.Fishel@Sun.COM }
201*8940SRandy.Fishel@Sun.COM if (errno == EINTR)
202*8940SRandy.Fishel@Sun.COM goto err;
203*8940SRandy.Fishel@Sun.COM
204*8940SRandy.Fishel@Sun.COM /* next message/response */
205*8940SRandy.Fishel@Sun.COM m++;
206*8940SRandy.Fishel@Sun.COM r++;
207*8940SRandy.Fishel@Sun.COM }
208*8940SRandy.Fishel@Sun.COM return (PAM_SUCCESS);
209*8940SRandy.Fishel@Sun.COM
210*8940SRandy.Fishel@Sun.COM err:
211*8940SRandy.Fishel@Sun.COM free_resp(i, r);
212*8940SRandy.Fishel@Sun.COM *resp = NULL;
213*8940SRandy.Fishel@Sun.COM return (PAM_CONV_ERR);
214*8940SRandy.Fishel@Sun.COM }
215