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 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 * 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 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 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