xref: /illumos-gate/usr/src/cmd/power/pm_pam_conv.c (revision 5009f788)
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