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