Annotation of embedaddon/sudo/src/tgetpass.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (c) 1996, 1998-2005, 2007-2011
        !             3:  *     Todd C. Miller <Todd.Miller@courtesan.com>
        !             4:  *
        !             5:  * Permission to use, copy, modify, and distribute this software for any
        !             6:  * purpose with or without fee is hereby granted, provided that the above
        !             7:  * copyright notice and this permission notice appear in all copies.
        !             8:  *
        !             9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            16:  *
        !            17:  * Sponsored in part by the Defense Advanced Research Projects
        !            18:  * Agency (DARPA) and Air Force Research Laboratory, Air Force
        !            19:  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
        !            20:  */
        !            21: 
        !            22: #ifdef __TANDEM
        !            23: # include <floss.h>
        !            24: #endif
        !            25: 
        !            26: #include <config.h>
        !            27: 
        !            28: #include <sys/types.h>
        !            29: #include <sys/param.h>
        !            30: #include <stdio.h>
        !            31: #ifdef STDC_HEADERS
        !            32: # include <stdlib.h>
        !            33: # include <stddef.h>
        !            34: #else
        !            35: # ifdef HAVE_STDLIB_H
        !            36: #  include <stdlib.h>
        !            37: # endif
        !            38: #endif /* STDC_HEADERS */
        !            39: #ifdef HAVE_STRING_H
        !            40: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
        !            41: #  include <memory.h>
        !            42: # endif
        !            43: # include <string.h>
        !            44: #endif /* HAVE_STRING_H */
        !            45: #ifdef HAVE_STRINGS_H
        !            46: # include <strings.h>
        !            47: #endif /* HAVE_STRINGS_H */
        !            48: #ifdef HAVE_UNISTD_H
        !            49: # include <unistd.h>
        !            50: #endif /* HAVE_UNISTD_H */
        !            51: #include <pwd.h>
        !            52: #include <errno.h>
        !            53: #include <signal.h>
        !            54: #include <fcntl.h>
        !            55: 
        !            56: #include "sudo.h"
        !            57: 
        !            58: static volatile sig_atomic_t signo[NSIG];
        !            59: 
        !            60: static void handler(int);
        !            61: static char *getln(int, char *, size_t, int);
        !            62: static char *sudo_askpass(const char *, const char *);
        !            63: 
        !            64: #ifdef _PATH_SUDO_ASKPASS
        !            65: const char *askpass_path = _PATH_SUDO_ASKPASS;
        !            66: #else
        !            67: const char *askpass_path;
        !            68: #endif
        !            69: 
        !            70: /*
        !            71:  * Like getpass(3) but with timeout and echo flags.
        !            72:  */
        !            73: char *
        !            74: tgetpass(const char *prompt, int timeout, int flags)
        !            75: {
        !            76:     sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm;
        !            77:     sigaction_t savetstp, savettin, savettou, savepipe;
        !            78:     char *pass;
        !            79:     static const char *askpass;
        !            80:     static char buf[SUDO_PASS_MAX + 1];
        !            81:     int i, input, output, save_errno, neednl = 0, need_restart;
        !            82: 
        !            83:     (void) fflush(stdout);
        !            84: 
        !            85:     if (askpass == NULL) {
        !            86:        askpass = getenv("SUDO_ASKPASS");
        !            87:        if (askpass == NULL || *askpass == '\0')
        !            88:            askpass = askpass_path;
        !            89:     }
        !            90: 
        !            91:     /* If no tty present and we need to disable echo, try askpass. */
        !            92:     if (!ISSET(flags, TGP_STDIN|TGP_ECHO|TGP_ASKPASS|TGP_NOECHO_TRY) &&
        !            93:        !tty_present()) {
        !            94:        if (askpass == NULL || getenv("DISPLAY") == NULL) {
        !            95:            warningx(_("no tty present and no askpass program specified"));
        !            96:            return NULL;
        !            97:        }
        !            98:        SET(flags, TGP_ASKPASS);
        !            99:     }
        !           100: 
        !           101:     /* If using a helper program to get the password, run it instead. */
        !           102:     if (ISSET(flags, TGP_ASKPASS)) {
        !           103:        if (askpass == NULL || *askpass == '\0')
        !           104:            errorx(1, _("no askpass program specified, try setting SUDO_ASKPASS"));
        !           105:        return sudo_askpass(askpass, prompt);
        !           106:     }
        !           107: 
        !           108: restart:
        !           109:     for (i = 0; i < NSIG; i++)
        !           110:        signo[i] = 0;
        !           111:     pass = NULL;
        !           112:     save_errno = 0;
        !           113:     need_restart = 0;
        !           114:     /* Open /dev/tty for reading/writing if possible else use stdin/stderr. */
        !           115:     if (ISSET(flags, TGP_STDIN) ||
        !           116:        (input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
        !           117:        input = STDIN_FILENO;
        !           118:        output = STDERR_FILENO;
        !           119:     }
        !           120: 
        !           121:     /*
        !           122:      * If we are using a tty but are not the foreground pgrp this will
        !           123:      * generate SIGTTOU, so do it *before* installing the signal handlers.
        !           124:      */
        !           125:     if (!ISSET(flags, TGP_ECHO)) {
        !           126:        if (ISSET(flags, TGP_MASK))
        !           127:            neednl = term_cbreak(input);
        !           128:        else
        !           129:            neednl = term_noecho(input);
        !           130:     }
        !           131: 
        !           132:     /*
        !           133:      * Catch signals that would otherwise cause the user to end
        !           134:      * up with echo turned off in the shell.
        !           135:      */
        !           136:     zero_bytes(&sa, sizeof(sa));
        !           137:     sigemptyset(&sa.sa_mask);
        !           138:     sa.sa_flags = SA_INTERRUPT;        /* don't restart system calls */
        !           139:     sa.sa_handler = handler;
        !           140:     (void) sigaction(SIGALRM, &sa, &savealrm);
        !           141:     (void) sigaction(SIGINT, &sa, &saveint);
        !           142:     (void) sigaction(SIGHUP, &sa, &savehup);
        !           143:     (void) sigaction(SIGQUIT, &sa, &savequit);
        !           144:     (void) sigaction(SIGTERM, &sa, &saveterm);
        !           145:     (void) sigaction(SIGTSTP, &sa, &savetstp);
        !           146:     (void) sigaction(SIGTTIN, &sa, &savettin);
        !           147:     (void) sigaction(SIGTTOU, &sa, &savettou);
        !           148: 
        !           149:     /* Ignore SIGPIPE in case stdin is a pipe and TGP_STDIN is set */
        !           150:     sa.sa_handler = SIG_IGN;
        !           151:     (void) sigaction(SIGPIPE, &sa, &savepipe);
        !           152: 
        !           153:     if (prompt) {
        !           154:        if (write(output, prompt, strlen(prompt)) == -1)
        !           155:            goto restore;
        !           156:     }
        !           157: 
        !           158:     if (timeout > 0)
        !           159:        alarm(timeout);
        !           160:     pass = getln(input, buf, sizeof(buf), ISSET(flags, TGP_MASK));
        !           161:     alarm(0);
        !           162:     save_errno = errno;
        !           163: 
        !           164:     if (neednl || pass == NULL) {
        !           165:        if (write(output, "\n", 1) == -1)
        !           166:            goto restore;
        !           167:     }
        !           168: 
        !           169: restore:
        !           170:     /* Restore old tty settings and signals. */
        !           171:     if (!ISSET(flags, TGP_ECHO))
        !           172:        term_restore(input, 1);
        !           173:     (void) sigaction(SIGALRM, &savealrm, NULL);
        !           174:     (void) sigaction(SIGINT, &saveint, NULL);
        !           175:     (void) sigaction(SIGHUP, &savehup, NULL);
        !           176:     (void) sigaction(SIGQUIT, &savequit, NULL);
        !           177:     (void) sigaction(SIGTERM, &saveterm, NULL);
        !           178:     (void) sigaction(SIGTSTP, &savetstp, NULL);
        !           179:     (void) sigaction(SIGTTIN, &savettin, NULL);
        !           180:     (void) sigaction(SIGTTOU, &savettou, NULL);
        !           181:     (void) sigaction(SIGTTOU, &savepipe, NULL);
        !           182:     if (input != STDIN_FILENO)
        !           183:        (void) close(input);
        !           184: 
        !           185:     /*
        !           186:      * If we were interrupted by a signal, resend it to ourselves
        !           187:      * now that we have restored the signal handlers.
        !           188:      */
        !           189:     for (i = 0; i < NSIG; i++) {
        !           190:        if (signo[i]) {
        !           191:            kill(getpid(), i);
        !           192:            switch (i) {
        !           193:                case SIGTSTP:
        !           194:                case SIGTTIN:
        !           195:                case SIGTTOU:
        !           196:                    need_restart = 1;
        !           197:                    break;
        !           198:            }
        !           199:        }
        !           200:     }
        !           201:     if (need_restart)
        !           202:        goto restart;
        !           203: 
        !           204:     if (save_errno)
        !           205:        errno = save_errno;
        !           206:     return pass;
        !           207: }
        !           208: 
        !           209: /*
        !           210:  * Fork a child and exec sudo-askpass to get the password from the user.
        !           211:  */
        !           212: static char *
        !           213: sudo_askpass(const char *askpass, const char *prompt)
        !           214: {
        !           215:     static char buf[SUDO_PASS_MAX + 1], *pass;
        !           216:     sigaction_t sa, saved_sa_pipe;
        !           217:     int pfd[2];
        !           218:     pid_t pid;
        !           219: 
        !           220:     if (pipe(pfd) == -1)
        !           221:        error(1, _("unable to create pipe"));
        !           222: 
        !           223:     if ((pid = fork()) == -1)
        !           224:        error(1, _("unable to fork"));
        !           225: 
        !           226:     if (pid == 0) {
        !           227:        /* child, point stdout to output side of the pipe and exec askpass */
        !           228:        if (dup2(pfd[1], STDOUT_FILENO) == -1) {
        !           229:            warning("dup2");
        !           230:            _exit(255);
        !           231:        }
        !           232:        (void) setuid(ROOT_UID);
        !           233:        if (setgid(user_details.gid)) {
        !           234:            warning(_("unable to set gid to %u"), (unsigned int)user_details.gid);
        !           235:            _exit(255);
        !           236:        }
        !           237:        if (setuid(user_details.uid)) {
        !           238:            warning(_("unable to set uid to %u"), (unsigned int)user_details.uid);
        !           239:            _exit(255);
        !           240:        }
        !           241:        closefrom(STDERR_FILENO + 1);
        !           242:        execl(askpass, askpass, prompt, (char *)NULL);
        !           243:        warning(_("unable to run %s"), askpass);
        !           244:        _exit(255);
        !           245:     }
        !           246: 
        !           247:     /* Ignore SIGPIPE in case child exits prematurely */
        !           248:     zero_bytes(&sa, sizeof(sa));
        !           249:     sigemptyset(&sa.sa_mask);
        !           250:     sa.sa_flags = SA_INTERRUPT;
        !           251:     sa.sa_handler = SIG_IGN;
        !           252:     (void) sigaction(SIGPIPE, &sa, &saved_sa_pipe);
        !           253: 
        !           254:     /* Get response from child (askpass) and restore SIGPIPE handler */
        !           255:     (void) close(pfd[1]);
        !           256:     pass = getln(pfd[0], buf, sizeof(buf), 0);
        !           257:     (void) close(pfd[0]);
        !           258:     (void) sigaction(SIGPIPE, &saved_sa_pipe, NULL);
        !           259: 
        !           260:     return pass;
        !           261: }
        !           262: 
        !           263: extern int term_erase, term_kill;
        !           264: 
        !           265: static char *
        !           266: getln(int fd, char *buf, size_t bufsiz, int feedback)
        !           267: {
        !           268:     size_t left = bufsiz;
        !           269:     ssize_t nr = -1;
        !           270:     char *cp = buf;
        !           271:     char c = '\0';
        !           272: 
        !           273:     if (left == 0) {
        !           274:        errno = EINVAL;
        !           275:        return NULL;                    /* sanity */
        !           276:     }
        !           277: 
        !           278:     while (--left) {
        !           279:        nr = read(fd, &c, 1);
        !           280:        if (nr != 1 || c == '\n' || c == '\r')
        !           281:            break;
        !           282:        if (feedback) {
        !           283:            if (c == term_kill) {
        !           284:                while (cp > buf) {
        !           285:                    if (write(fd, "\b \b", 3) == -1)
        !           286:                        break;
        !           287:                    --cp;
        !           288:                }
        !           289:                left = bufsiz;
        !           290:                continue;
        !           291:            } else if (c == term_erase) {
        !           292:                if (cp > buf) {
        !           293:                    if (write(fd, "\b \b", 3) == -1)
        !           294:                        break;
        !           295:                    --cp;
        !           296:                    left++;
        !           297:                }
        !           298:                continue;
        !           299:            }
        !           300:            if (write(fd, "*", 1) == -1)
        !           301:                /* shut up glibc */;
        !           302:        }
        !           303:        *cp++ = c;
        !           304:     }
        !           305:     *cp = '\0';
        !           306:     if (feedback) {
        !           307:        /* erase stars */
        !           308:        while (cp > buf) {
        !           309:            if (write(fd, "\b \b", 3) == -1)
        !           310:                break;
        !           311:            --cp;
        !           312:        }
        !           313:     }
        !           314: 
        !           315:     return nr == 1 ? buf : NULL;
        !           316: }
        !           317: 
        !           318: static void
        !           319: handler(int s)
        !           320: {
        !           321:     if (s != SIGALRM)
        !           322:        signo[s] = 1;
        !           323: }
        !           324: 
        !           325: int
        !           326: tty_present(void)
        !           327: {
        !           328:     int fd;
        !           329: 
        !           330:     if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) != -1)
        !           331:        close(fd);
        !           332:     return fd != -1;
        !           333: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>