623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel/*
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * CDDL HEADER START
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel *
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * The contents of this file are subject to the terms of the
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * Common Development and Distribution License (the "License").
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * You may not use this file except in compliance with the License.
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel *
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * or http://www.opensolaris.org/os/licensing.
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * See the License for the specific language governing permissions
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * and limitations under the License.
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel *
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * When distributing Covered Code, include this CDDL HEADER in each
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * If applicable, add the following below this CDDL HEADER, with the
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * fields enclosed by brackets "[]" replaced with your own identifying
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * information: Portions Copyright [yyyy] [name of copyright owner]
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel *
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * CDDL HEADER END
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel */
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel/*
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * Use is subject to license terms.
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel */
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel/*
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * This file has all of the PAM related code for sys-suspend. It is
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * part of it's own file, as these could be part of some bigger item
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * that can handle generic PAM facilities (certainly the getinput()
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * function could be in a common library). However, as that does not
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * yet exist, we replicate it here so we can get the job done.
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel */
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel#define __EXTENSIONS__ /* to expose flockfile and friends in stdio.h */
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel#include <errno.h>
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel#include <libgen.h>
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel#include <malloc.h>
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel#include <signal.h>
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel#include <stdio.h>
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel#include <stdlib.h>
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel#include <strings.h>
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel#include <stropts.h>
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel#include <unistd.h>
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel#include <termio.h>
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel#include <security/pam_appl.h>
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishelstatic int ctl_c; /* was the conversation interrupted? */
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel/* ARGSUSED 1 */
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishelstatic void
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishelinterrupt(int x)
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel{
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel ctl_c = 1;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel}
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel/*
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * getinput -- read user input from stdin abort on ^C
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel *
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * Entry noecho == TRUE, don't echo input.
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel *
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * Exit User's input.
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * If interrupted, send SIGINT to caller for processing.
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel */
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishelstatic char *
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishelgetinput(int noecho)
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel{
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel struct termio tty;
5009f7885e2c6a7e13fe9ad876bd812add4754efIgor Kozhukhov unsigned short tty_flags = 0;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel char input[PAM_MAX_RESP_SIZE + 1];
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel int c;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel int i = 0;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel void (*sig)(int);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel ctl_c = 0;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel sig = signal(SIGINT, interrupt);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel if (noecho) {
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel (void) ioctl(fileno(stdin), TCGETA, &tty);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel tty_flags = tty.c_lflag;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel tty.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel (void) ioctl(fileno(stdin), TCSETAF, &tty);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel }
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel /* go to end, but don't overflow PAM_MAX_RESP_SIZE */
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel flockfile(stdin);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel while (ctl_c == 0 &&
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel (c = getchar_unlocked()) != '\n' &&
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel c != '\r' &&
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel c != EOF) {
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel if (i < PAM_MAX_RESP_SIZE) {
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel input[i++] = (char)c;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel }
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel }
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel funlockfile(stdin);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel input[i] = '\0';
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel if (noecho) {
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel tty.c_lflag = tty_flags;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel (void) ioctl(fileno(stdin), TCSETAW, &tty);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel (void) fputc('\n', stdout);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel }
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel (void) signal(SIGINT, sig);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel if (ctl_c == 1)
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel (void) kill(getpid(), SIGINT);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel return (strdup(input));
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel}
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel/*
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * Service modules don't clean up responses if an error is returned.
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * Free responses here.
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel */
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishelstatic void
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishelfree_resp(int num_msg, struct pam_response *pr)
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel{
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel int i;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel struct pam_response *r = pr;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel if (pr == NULL)
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel return;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel for (i = 0; i < num_msg; i++, r++) {
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel if (r->resp) {
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel /* clear before freeing -- may be a password */
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel bzero(r->resp, strlen(r->resp));
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel free(r->resp);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel r->resp = NULL;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel }
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel }
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel free(pr);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel}
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel/* ARGSUSED */
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishelint
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishelpam_tty_conv(int num_msg, struct pam_message **mess,
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel struct pam_response **resp, void *my_data)
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel{
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel struct pam_message *m = *mess;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel struct pam_response *r = calloc(num_msg, sizeof (struct pam_response));
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel int i;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel if (num_msg >= PAM_MAX_NUM_MSG) {
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel (void) fprintf(stderr, "too many messages %d >= %d\n",
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel num_msg, PAM_MAX_NUM_MSG);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel free(r);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel *resp = NULL;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel return (PAM_CONV_ERR);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel }
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel /* Talk it out */
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel *resp = r;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel for (i = 0; i < num_msg; i++) {
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel int echo_off;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel /* bad message from service module */
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel if (m->msg == NULL) {
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel (void) fprintf(stderr, "message[%d]: %d/NULL\n",
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel i, m->msg_style);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel goto err;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel }
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel /*
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * fix up final newline:
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * removed for prompts
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel * added back for messages
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel */
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel if (m->msg[strlen(m->msg)] == '\n')
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel m->msg[strlen(m->msg)] = '\0';
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel r->resp = NULL;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel r->resp_retcode = 0;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel echo_off = 0;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel switch (m->msg_style) {
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel case PAM_PROMPT_ECHO_OFF:
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel echo_off = 1;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel /*FALLTHROUGH*/
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel case PAM_PROMPT_ECHO_ON:
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel (void) fputs(m->msg, stdout);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel r->resp = getinput(echo_off);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel break;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel case PAM_ERROR_MSG:
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel (void) fputs(m->msg, stderr);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel (void) fputc('\n', stderr);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel break;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel case PAM_TEXT_INFO:
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel (void) fputs(m->msg, stdout);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel (void) fputc('\n', stdout);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel break;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel default:
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel (void) fprintf(stderr, "message[%d]: unknown type "
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel "%d/val=\"%s\"\n",
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel i, m->msg_style, m->msg);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel /* error, service module won't clean up */
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel goto err;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel }
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel if (errno == EINTR)
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel goto err;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel /* next message/response */
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel m++;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel r++;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel }
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel return (PAM_SUCCESS);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishelerr:
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel free_resp(i, r);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel *resp = NULL;
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel return (PAM_CONV_ERR);
623ec8b0965ca16c95dab78c0bd2af81733a0253Randy Fishel}