Rework source layout in preparation for modular sudo.
This commit is contained in:
127
src/aix.c
Normal file
127
src/aix.c
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif /* STDC_HEADERS */
|
||||
#include <usersec.h>
|
||||
|
||||
#include <compat.h>
|
||||
|
||||
#ifdef HAVE_GETUSERATTR
|
||||
|
||||
#ifndef HAVE_SETRLIMIT64
|
||||
# define setrlimit64(a, b) setrlimit(a, b)
|
||||
# define rlimit64 rlimit
|
||||
# define rlim64_t rlim_t
|
||||
# define RLIM64_INFINITY RLIM_INFINITY
|
||||
#endif /* HAVE_SETRLIMIT64 */
|
||||
|
||||
#ifndef RLIM_SAVED_MAX
|
||||
# define RLIM_SAVED_MAX RLIM64_INFINITY
|
||||
#endif
|
||||
|
||||
struct aix_limit {
|
||||
int resource;
|
||||
char *soft;
|
||||
char *hard;
|
||||
int factor;
|
||||
};
|
||||
|
||||
static struct aix_limit aix_limits[] = {
|
||||
{ RLIMIT_FSIZE, S_UFSIZE, S_UFSIZE_HARD, 512 },
|
||||
{ RLIMIT_CPU, S_UCPU, S_UCPU_HARD, 1 },
|
||||
{ RLIMIT_DATA, S_UDATA, S_UDATA_HARD, 512 },
|
||||
{ RLIMIT_STACK, S_USTACK, S_USTACK_HARD, 512 },
|
||||
{ RLIMIT_RSS, S_URSS, S_URSS_HARD, 512 },
|
||||
{ RLIMIT_CORE, S_UCORE, S_UCORE_HARD, 512 },
|
||||
{ RLIMIT_NOFILE, S_UNOFILE, S_UNOFILE_HARD, 1 }
|
||||
};
|
||||
|
||||
static int
|
||||
aix_getlimit(user, lim, valp)
|
||||
char *user;
|
||||
char *lim;
|
||||
rlim64_t *valp;
|
||||
{
|
||||
int val;
|
||||
|
||||
if (getuserattr(user, lim, &val, SEC_INT) != 0 &&
|
||||
getuserattr("default", lim, &val, SEC_INT) != 0) {
|
||||
return(-1);
|
||||
}
|
||||
*valp = val;
|
||||
return(0);
|
||||
}
|
||||
|
||||
void
|
||||
aix_setlimits(user)
|
||||
char *user;
|
||||
{
|
||||
struct rlimit64 rlim;
|
||||
rlim64_t val;
|
||||
int n;
|
||||
|
||||
/*
|
||||
* For each resource limit, get the soft/hard values for the user
|
||||
* and set those values via setrlimit64(). Must be run as euid 0.
|
||||
*/
|
||||
for (n = 0; n < sizeof(aix_limits) / sizeof(aix_limits[0]); n++) {
|
||||
/*
|
||||
* We have two strategies, depending on whether or not the
|
||||
* hard limit has been defined.
|
||||
*/
|
||||
if (aix_getlimit(user, aix_limits[n].hard, &val) == 0) {
|
||||
rlim.rlim_max = val == -1 ? RLIM64_INFINITY : val * aix_limits[n].factor;
|
||||
if (aix_getlimit(user, aix_limits[n].soft, &val) == 0)
|
||||
rlim.rlim_cur = val == -1 ? RLIM64_INFINITY : val * aix_limits[n].factor;
|
||||
else
|
||||
rlim.rlim_cur = rlim.rlim_max; /* soft not specd, use hard */
|
||||
} else {
|
||||
/* No hard limit set, try soft limit. */
|
||||
if (aix_getlimit(user, aix_limits[n].soft, &val) == 0)
|
||||
rlim.rlim_cur = val == -1 ? RLIM64_INFINITY : val * aix_limits[n].factor;
|
||||
|
||||
/* Set hard limit per AIX /etc/security/limits documentation. */
|
||||
switch (aix_limits[n].resource) {
|
||||
case RLIMIT_CPU:
|
||||
case RLIMIT_FSIZE:
|
||||
rlim.rlim_max = rlim.rlim_cur;
|
||||
break;
|
||||
case RLIMIT_STACK:
|
||||
rlim.rlim_max = RLIM_SAVED_MAX;
|
||||
break;
|
||||
default:
|
||||
rlim.rlim_max = RLIM64_INFINITY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
(void)setrlimit64(aix_limits[n].resource, &rlim);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_GETUSERATTR */
|
224
src/alloc.c
Normal file
224
src/alloc.c
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (c) 1999-2005, 2007
|
||||
* Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Sponsored in part by the Defense Advanced Research Projects
|
||||
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif /* STDC_HEADERS */
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif /* HAVE_STRING_H */
|
||||
#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
|
||||
# include <malloc.h>
|
||||
#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#include "sudo.h"
|
||||
|
||||
/*
|
||||
* If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t
|
||||
* could be signed (as it is on SunOS 4.x). This just means that
|
||||
* emalloc2() and erealloc3() cannot allocate huge amounts on such a
|
||||
* platform but that is OK since sudo doesn't need to do so anyway.
|
||||
*/
|
||||
#ifndef SIZE_MAX
|
||||
# ifdef SIZE_T_MAX
|
||||
# define SIZE_MAX SIZE_T_MAX
|
||||
# else
|
||||
# define SIZE_MAX INT_MAX
|
||||
# endif /* SIZE_T_MAX */
|
||||
#endif /* SIZE_MAX */
|
||||
|
||||
/*
|
||||
* emalloc() calls the system malloc(3) and exits with an error if
|
||||
* malloc(3) fails.
|
||||
*/
|
||||
void *
|
||||
emalloc(size)
|
||||
size_t size;
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
if (size == 0)
|
||||
errorx(1, "internal error, tried to emalloc(0)");
|
||||
|
||||
if ((ptr = malloc(size)) == NULL)
|
||||
errorx(1, "unable to allocate memory");
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* emalloc2() allocates nmemb * size bytes and exits with an error
|
||||
* if overflow would occur or if the system malloc(3) fails.
|
||||
*/
|
||||
void *
|
||||
emalloc2(nmemb, size)
|
||||
size_t nmemb;
|
||||
size_t size;
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
if (nmemb == 0 || size == 0)
|
||||
errorx(1, "internal error, tried to emalloc2(0)");
|
||||
if (nmemb > SIZE_MAX / size)
|
||||
errorx(1, "internal error, emalloc2() overflow");
|
||||
|
||||
size *= nmemb;
|
||||
if ((ptr = malloc(size)) == NULL)
|
||||
errorx(1, "unable to allocate memory");
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* erealloc() calls the system realloc(3) and exits with an error if
|
||||
* realloc(3) fails. You can call erealloc() with a NULL pointer even
|
||||
* if the system realloc(3) does not support this.
|
||||
*/
|
||||
void *
|
||||
erealloc(ptr, size)
|
||||
void *ptr;
|
||||
size_t size;
|
||||
{
|
||||
|
||||
if (size == 0)
|
||||
errorx(1, "internal error, tried to erealloc(0)");
|
||||
|
||||
ptr = ptr ? realloc(ptr, size) : malloc(size);
|
||||
if (ptr == NULL)
|
||||
errorx(1, "unable to allocate memory");
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* erealloc3() realloc(3)s nmemb * size bytes and exits with an error
|
||||
* if overflow would occur or if the system malloc(3)/realloc(3) fails.
|
||||
* You can call erealloc() with a NULL pointer even if the system realloc(3)
|
||||
* does not support this.
|
||||
*/
|
||||
void *
|
||||
erealloc3(ptr, nmemb, size)
|
||||
void *ptr;
|
||||
size_t nmemb;
|
||||
size_t size;
|
||||
{
|
||||
|
||||
if (nmemb == 0 || size == 0)
|
||||
errorx(1, "internal error, tried to erealloc3(0)");
|
||||
if (nmemb > SIZE_MAX / size)
|
||||
errorx(1, "internal error, erealloc3() overflow");
|
||||
|
||||
size *= nmemb;
|
||||
ptr = ptr ? realloc(ptr, size) : malloc(size);
|
||||
if (ptr == NULL)
|
||||
errorx(1, "unable to allocate memory");
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* estrdup() is like strdup(3) except that it exits with an error if
|
||||
* malloc(3) fails. NOTE: unlike strdup(3), estrdup(NULL) is legal.
|
||||
*/
|
||||
char *
|
||||
estrdup(src)
|
||||
const char *src;
|
||||
{
|
||||
char *dst = NULL;
|
||||
size_t size;
|
||||
|
||||
if (src != NULL) {
|
||||
size = strlen(src) + 1;
|
||||
dst = (char *) emalloc(size);
|
||||
(void) memcpy(dst, src, size);
|
||||
}
|
||||
return(dst);
|
||||
}
|
||||
|
||||
/*
|
||||
* easprintf() calls vasprintf() and exits with an error if vasprintf()
|
||||
* returns -1 (out of memory).
|
||||
*/
|
||||
int
|
||||
#ifdef __STDC__
|
||||
easprintf(char **ret, const char *fmt, ...)
|
||||
#else
|
||||
easprintf(ret, fmt, va_alist)
|
||||
char **ret;
|
||||
const char *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
int len;
|
||||
va_list ap;
|
||||
#ifdef __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
len = vasprintf(ret, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (len == -1)
|
||||
errorx(1, "unable to allocate memory");
|
||||
return(len);
|
||||
}
|
||||
|
||||
/*
|
||||
* evasprintf() calls vasprintf() and exits with an error if vasprintf()
|
||||
* returns -1 (out of memory).
|
||||
*/
|
||||
int
|
||||
evasprintf(ret, format, args)
|
||||
char **ret;
|
||||
const char *format;
|
||||
va_list args;
|
||||
{
|
||||
int len;
|
||||
|
||||
if ((len = vasprintf(ret, format, args)) == -1)
|
||||
errorx(1, "unable to allocate memory");
|
||||
return(len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper for free(3) so we can depend on C89 semantics.
|
||||
*/
|
||||
void
|
||||
efree(ptr)
|
||||
void *ptr;
|
||||
{
|
||||
if (ptr != NULL)
|
||||
free(ptr);
|
||||
}
|
76
src/audit.c
Normal file
76
src/audit.c
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif /* STDC_HEADERS */
|
||||
#ifdef __STDC__
|
||||
# include <stdarg.h>
|
||||
#else
|
||||
# include <varargs.h>
|
||||
#endif
|
||||
|
||||
#include "compat.h"
|
||||
#include "logging.h"
|
||||
|
||||
#ifdef HAVE_BSM_AUDIT
|
||||
# include "bsm_audit.h"
|
||||
#endif
|
||||
|
||||
void
|
||||
#ifdef __STDC__
|
||||
audit_success(char **exec_args)
|
||||
#else
|
||||
audit_success(exec_args)
|
||||
const char **exec_args;
|
||||
#endif
|
||||
{
|
||||
#ifdef HAVE_BSM_AUDIT
|
||||
bsm_audit_success(exec_args);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
#ifdef __STDC__
|
||||
audit_failure(char **exec_args, char const *const fmt, ...)
|
||||
#else
|
||||
audit_failure(exec_args, fmt, va_alist)
|
||||
const char **exec_args;
|
||||
char const *const fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
#ifdef __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
#ifdef HAVE_BSM_AUDIT
|
||||
bsm_audit_failure(exec_args, fmt, ap);
|
||||
#endif
|
||||
va_end(ap);
|
||||
}
|
173
src/bsm_audit.c
Normal file
173
src/bsm_audit.c
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Christian S.J. Peron
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <bsm/audit.h>
|
||||
#include <bsm/libbsm.h>
|
||||
#include <bsm/audit_uevents.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <pwd.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void log_error(int flags, const char *fmt, ...) __attribute__((__noreturn__));
|
||||
|
||||
static int
|
||||
audit_sudo_selected(int sf)
|
||||
{
|
||||
auditinfo_addr_t ainfo_addr;
|
||||
struct au_mask *mask;
|
||||
auditinfo_t ainfo;
|
||||
int rc, sorf;
|
||||
|
||||
if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) < 0) {
|
||||
if (errno == ENOSYS) {
|
||||
if (getaudit(&ainfo) < 0)
|
||||
log_error(0, "getaudit: failed");
|
||||
mask = &ainfo.ai_mask;
|
||||
} else
|
||||
log_error(0, "getaudit: failed");
|
||||
} else
|
||||
mask = &ainfo_addr.ai_mask;
|
||||
sorf = (sf == 0) ? AU_PRS_SUCCESS : AU_PRS_FAILURE;
|
||||
rc = au_preselect(AUE_sudo, mask, sorf, AU_PRS_REREAD);
|
||||
return (rc);
|
||||
}
|
||||
|
||||
void
|
||||
bsm_audit_success(char **exec_args)
|
||||
{
|
||||
auditinfo_addr_t ainfo_addr;
|
||||
auditinfo_t ainfo;
|
||||
token_t *tok;
|
||||
au_id_t auid;
|
||||
long au_cond;
|
||||
int aufd;
|
||||
pid_t pid;
|
||||
|
||||
pid = getpid();
|
||||
/*
|
||||
* If we are not auditing, don't cut an audit record; just return.
|
||||
*/
|
||||
if (auditon(A_GETCOND, (caddr_t)&au_cond, sizeof(long)) < 0) {
|
||||
if (errno == ENOSYS)
|
||||
return;
|
||||
log_error(0, "Could not determine audit condition");
|
||||
}
|
||||
if (au_cond == AUC_NOAUDIT)
|
||||
return;
|
||||
/*
|
||||
* Check to see if the preselection masks are interested in seeing
|
||||
* this event.
|
||||
*/
|
||||
if (!audit_sudo_selected(0))
|
||||
return;
|
||||
if (getauid(&auid) < 0)
|
||||
log_error(0, "getauid failed");
|
||||
if ((aufd = au_open()) == -1)
|
||||
log_error(0, "au_open: failed");
|
||||
if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) {
|
||||
tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(),
|
||||
getuid(), pid, pid, &ainfo_addr.ai_termid);
|
||||
} else if (errno == ENOSYS) {
|
||||
/*
|
||||
* NB: We should probably watch out for ERANGE here.
|
||||
*/
|
||||
if (getaudit(&ainfo) < 0)
|
||||
log_error(0, "getaudit: failed");
|
||||
tok = au_to_subject(auid, geteuid(), getegid(), getuid(),
|
||||
getuid(), pid, pid, &ainfo.ai_termid);
|
||||
} else
|
||||
log_error(0, "getaudit: failed");
|
||||
if (tok == NULL)
|
||||
log_error(0, "au_to_subject: failed");
|
||||
au_write(aufd, tok);
|
||||
tok = au_to_exec_args(exec_args);
|
||||
if (tok == NULL)
|
||||
log_error(0, "au_to_exec_args: failed");
|
||||
au_write(aufd, tok);
|
||||
tok = au_to_return32(0, 0);
|
||||
if (tok == NULL)
|
||||
log_error(0, "au_to_return32: failed");
|
||||
au_write(aufd, tok);
|
||||
if (au_close(aufd, 1, AUE_sudo) == -1)
|
||||
log_error(0, "unable to commit audit record");
|
||||
}
|
||||
|
||||
void
|
||||
bsm_audit_failure(char **exec_args, char const *const fmt, va_list ap)
|
||||
{
|
||||
auditinfo_addr_t ainfo_addr;
|
||||
auditinfo_t ainfo;
|
||||
char text[256];
|
||||
token_t *tok;
|
||||
long au_cond;
|
||||
au_id_t auid;
|
||||
pid_t pid;
|
||||
int aufd;
|
||||
|
||||
pid = getpid();
|
||||
/*
|
||||
* If we are not auditing, don't cut an audit record; just return.
|
||||
*/
|
||||
if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
|
||||
if (errno == ENOSYS)
|
||||
return;
|
||||
log_error(0, "Could not determine audit condition");
|
||||
}
|
||||
if (au_cond == AUC_NOAUDIT)
|
||||
return;
|
||||
if (!audit_sudo_selected(1))
|
||||
return;
|
||||
if (getauid(&auid) < 0)
|
||||
log_error(0, "getauid: failed");
|
||||
if ((aufd = au_open()) == -1)
|
||||
log_error(0, "au_open: failed");
|
||||
if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) {
|
||||
tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(),
|
||||
getuid(), pid, pid, &ainfo_addr.ai_termid);
|
||||
} else if (errno == ENOSYS) {
|
||||
if (getaudit(&ainfo) < 0)
|
||||
log_error(0, "getaudit: failed");
|
||||
tok = au_to_subject(auid, geteuid(), getegid(), getuid(),
|
||||
getuid(), pid, pid, &ainfo.ai_termid);
|
||||
} else
|
||||
log_error(0, "getaudit: failed");
|
||||
if (tok == NULL)
|
||||
log_error(0, "au_to_subject: failed");
|
||||
au_write(aufd, tok);
|
||||
tok = au_to_exec_args(exec_args);
|
||||
if (tok == NULL)
|
||||
log_error(0, "au_to_exec_args: failed");
|
||||
au_write(aufd, tok);
|
||||
(void) vsnprintf(text, sizeof(text), fmt, ap);
|
||||
tok = au_to_text(text);
|
||||
if (tok == NULL)
|
||||
log_error(0, "au_to_text: failed");
|
||||
au_write(aufd, tok);
|
||||
tok = au_to_return32(EPERM, 1);
|
||||
if (tok == NULL)
|
||||
log_error(0, "au_to_return32: failed");
|
||||
au_write(aufd, tok);
|
||||
if (au_close(aufd, 1, AUE_sudo) == -1)
|
||||
log_error(0, "unable to commit audit record");
|
||||
}
|
23
src/bsm_audit.h
Normal file
23
src/bsm_audit.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Christian S.J. Peron
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _SUDO_BSM_AUDIT_H
|
||||
#define _SUDO_BSM_AUDIT_H
|
||||
|
||||
void bsm_audit_success(char **);
|
||||
void bsm_audit_failure(char **, char const * const, va_list);
|
||||
|
||||
#endif /* _SUDO_BSM_AUDIT_H */
|
129
src/error.c
Normal file
129
src/error.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <config.h>
|
||||
#include <compat.h>
|
||||
#include "error.h"
|
||||
|
||||
static void _warning __P((int, const char *, va_list));
|
||||
void cleanup __P((int));
|
||||
|
||||
void
|
||||
#ifdef __STDC__
|
||||
error(int eval, const char *fmt, ...)
|
||||
#else
|
||||
error(eval, fmt, va_alist)
|
||||
int eval;
|
||||
const char *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list ap;
|
||||
#ifdef __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
_warning(1, fmt, ap);
|
||||
va_end(ap);
|
||||
cleanup(0);
|
||||
exit(eval);
|
||||
}
|
||||
|
||||
void
|
||||
#ifdef __STDC__
|
||||
errorx(int eval, const char *fmt, ...)
|
||||
#else
|
||||
errorx(eval, fmt, va_alist)
|
||||
int eval;
|
||||
const char *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list ap;
|
||||
#ifdef __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
_warning(0, fmt, ap);
|
||||
va_end(ap);
|
||||
cleanup(0);
|
||||
exit(eval);
|
||||
}
|
||||
|
||||
void
|
||||
#ifdef __STDC__
|
||||
warning(const char *fmt, ...)
|
||||
#else
|
||||
warning(fmt, va_alist)
|
||||
const char *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list ap;
|
||||
#ifdef __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
_warning(1, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
#ifdef __STDC__
|
||||
warningx(const char *fmt, ...)
|
||||
#else
|
||||
warningx(fmt, va_alist)
|
||||
const char *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list ap;
|
||||
#ifdef __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
_warning(0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void
|
||||
_warning(use_errno, fmt, ap)
|
||||
int use_errno;
|
||||
const char *fmt;
|
||||
va_list ap;
|
||||
{
|
||||
int serrno = errno;
|
||||
|
||||
fputs(getprogname(), stderr);
|
||||
if (fmt != NULL) {
|
||||
fputs(": ", stderr);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
}
|
||||
if (use_errno) {
|
||||
fputs(": ", stderr);
|
||||
fputs(strerror(serrno), stderr);
|
||||
}
|
||||
putc('\n', stderr);
|
||||
}
|
177
src/fileops.c
Normal file
177
src/fileops.c
Normal file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (c) 1999-2005,2007,2009 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Sponsored in part by the Defense Advanced Research Projects
|
||||
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef HAVE_FLOCK
|
||||
# include <sys/file.h>
|
||||
#endif /* HAVE_FLOCK */
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif /* HAVE_STRING_H */
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
#include <fcntl.h>
|
||||
#if TIME_WITH_SYS_TIME
|
||||
# include <time.h>
|
||||
#endif
|
||||
#ifndef HAVE_TIMESPEC
|
||||
# include <emul/timespec.h>
|
||||
#endif
|
||||
|
||||
#include "sudo.h"
|
||||
|
||||
#ifndef LINE_MAX
|
||||
# define LINE_MAX 2048
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Update the access and modify times on an fd or file.
|
||||
*/
|
||||
int
|
||||
touch(fd, path, tsp)
|
||||
int fd;
|
||||
char *path;
|
||||
struct timespec *tsp;
|
||||
{
|
||||
struct timeval times[2];
|
||||
|
||||
if (tsp != NULL) {
|
||||
times[0].tv_sec = times[1].tv_sec = tsp->tv_sec;
|
||||
times[0].tv_usec = times[1].tv_usec = tsp->tv_nsec / 1000;
|
||||
}
|
||||
|
||||
#if defined(HAVE_FUTIME) || defined(HAVE_FUTIMES)
|
||||
if (fd != -1)
|
||||
return(futimes(fd, tsp ? times : NULL));
|
||||
else
|
||||
#endif
|
||||
if (path != NULL)
|
||||
return(utimes(path, tsp ? times : NULL));
|
||||
else
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock/unlock a file.
|
||||
*/
|
||||
#ifdef HAVE_LOCKF
|
||||
int
|
||||
lock_file(fd, lockit)
|
||||
int fd;
|
||||
int lockit;
|
||||
{
|
||||
int op = 0;
|
||||
|
||||
switch (lockit) {
|
||||
case SUDO_LOCK:
|
||||
op = F_LOCK;
|
||||
break;
|
||||
case SUDO_TLOCK:
|
||||
op = F_TLOCK;
|
||||
break;
|
||||
case SUDO_UNLOCK:
|
||||
op = F_ULOCK;
|
||||
break;
|
||||
}
|
||||
return(lockf(fd, op, 0) == 0);
|
||||
}
|
||||
#elif HAVE_FLOCK
|
||||
int
|
||||
lock_file(fd, lockit)
|
||||
int fd;
|
||||
int lockit;
|
||||
{
|
||||
int op = 0;
|
||||
|
||||
switch (lockit) {
|
||||
case SUDO_LOCK:
|
||||
op = LOCK_EX;
|
||||
break;
|
||||
case SUDO_TLOCK:
|
||||
op = LOCK_EX | LOCK_NB;
|
||||
break;
|
||||
case SUDO_UNLOCK:
|
||||
op = LOCK_UN;
|
||||
break;
|
||||
}
|
||||
return(flock(fd, op) == 0);
|
||||
}
|
||||
#else
|
||||
int
|
||||
lock_file(fd, lockit)
|
||||
int fd;
|
||||
int lockit;
|
||||
{
|
||||
#ifdef F_SETLK
|
||||
int func;
|
||||
struct flock lock;
|
||||
|
||||
lock.l_start = 0;
|
||||
lock.l_len = 0;
|
||||
lock.l_pid = getpid();
|
||||
lock.l_type = (lockit == SUDO_UNLOCK) ? F_UNLCK : F_WRLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
func = (lockit == SUDO_LOCK) ? F_SETLKW : F_SETLK;
|
||||
|
||||
return(fcntl(fd, func, &lock) == 0);
|
||||
#else
|
||||
return(TRUE);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Read a line of input, remove comments and strip off leading
|
||||
* and trailing spaces. Returns static storage that is reused.
|
||||
*/
|
||||
char *
|
||||
sudo_parseln(fp)
|
||||
FILE *fp;
|
||||
{
|
||||
size_t len;
|
||||
char *cp = NULL;
|
||||
static char buf[LINE_MAX];
|
||||
|
||||
if (fgets(buf, sizeof(buf), fp) != NULL) {
|
||||
/* Remove comments */
|
||||
if ((cp = strchr(buf, '#')) != NULL)
|
||||
*cp = '\0';
|
||||
|
||||
/* Trim leading and trailing whitespace/newline */
|
||||
len = strlen(buf);
|
||||
while (len > 0 && isspace((unsigned char)buf[len - 1]))
|
||||
buf[--len] = '\0';
|
||||
for (cp = buf; isblank(*cp); cp++)
|
||||
continue;
|
||||
}
|
||||
return(cp);
|
||||
}
|
285
src/lbuf.c
Normal file
285
src/lbuf.c
Normal file
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2009 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif /* STDC_HEADERS */
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif /* HAVE_STRING_H */
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
#include <ctype.h>
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
# include <termios.h>
|
||||
#else
|
||||
# ifdef HAVE_TERMIO_H
|
||||
# include <termio.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "sudo.h"
|
||||
#include "lbuf.h"
|
||||
|
||||
#if !defined(TIOCGSIZE) && defined(TIOCGWINSZ)
|
||||
# define TIOCGSIZE TIOCGWINSZ
|
||||
# define ttysize winsize
|
||||
# define ts_cols ws_col
|
||||
#endif
|
||||
|
||||
int
|
||||
get_ttycols()
|
||||
{
|
||||
char *p;
|
||||
int cols;
|
||||
#ifdef TIOCGSIZE
|
||||
struct ttysize win;
|
||||
|
||||
if (ioctl(STDERR_FILENO, TIOCGSIZE, &win) == 0 && win.ts_cols != 0)
|
||||
return((int)win.ts_cols);
|
||||
#endif
|
||||
|
||||
/* Fall back on $COLUMNS. */
|
||||
if ((p = getenv("COLUMNS")) == NULL || (cols = atoi(p)) <= 0)
|
||||
cols = 80;
|
||||
return(cols);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: add support for embedded newlines in lbufs
|
||||
*/
|
||||
|
||||
void
|
||||
lbuf_init(lbuf, buf, indent, continuation)
|
||||
struct lbuf *lbuf;
|
||||
char *buf;
|
||||
int indent;
|
||||
int continuation;
|
||||
{
|
||||
lbuf->continuation = continuation;
|
||||
lbuf->indent = indent;
|
||||
lbuf->len = 0;
|
||||
lbuf->size = 0;
|
||||
lbuf->buf = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
lbuf_destroy(lbuf)
|
||||
struct lbuf *lbuf;
|
||||
{
|
||||
efree(lbuf->buf);
|
||||
lbuf->buf = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Append strings to the buffer, expanding it as needed.
|
||||
*/
|
||||
void
|
||||
#ifdef __STDC__
|
||||
lbuf_append_quoted(struct lbuf *lbuf, const char *set, ...)
|
||||
#else
|
||||
lbuf_append_quoted(lbuf, set, va_alist)
|
||||
struct lbuf *lbuf;
|
||||
const char *set;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list ap;
|
||||
int len = 0;
|
||||
char *cp, *s;
|
||||
|
||||
#ifdef __STDC__
|
||||
va_start(ap, set);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
while ((s = va_arg(ap, char *)) != NULL) {
|
||||
len += strlen(s);
|
||||
for (cp = s; (cp = strpbrk(cp, set)) != NULL; cp++)
|
||||
len++;
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
/* Expand buffer as needed. */
|
||||
if (lbuf->len + len >= lbuf->size) {
|
||||
do {
|
||||
lbuf->size += 256;
|
||||
} while (lbuf->len + len >= lbuf->size);
|
||||
lbuf->buf = erealloc(lbuf->buf, lbuf->size);
|
||||
}
|
||||
|
||||
#ifdef __STDC__
|
||||
va_start(ap, set);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
/* Append each string. */
|
||||
while ((s = va_arg(ap, char *)) != NULL) {
|
||||
while ((cp = strpbrk(s, set)) != NULL) {
|
||||
len = (int)(cp - s);
|
||||
memcpy(lbuf->buf + lbuf->len, s, len);
|
||||
lbuf->len += len;
|
||||
lbuf->buf[lbuf->len++] = '\\';
|
||||
lbuf->buf[lbuf->len++] = *cp;
|
||||
s = cp + 1;
|
||||
}
|
||||
if (*s != '\0') {
|
||||
len = strlen(s);
|
||||
memcpy(lbuf->buf + lbuf->len, s, len);
|
||||
lbuf->len += len;
|
||||
}
|
||||
}
|
||||
lbuf->buf[lbuf->len] = '\0';
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Append strings to the buffer, expanding it as needed.
|
||||
*/
|
||||
void
|
||||
#ifdef __STDC__
|
||||
lbuf_append(struct lbuf *lbuf, ...)
|
||||
#else
|
||||
lbuf_append(lbuf, va_alist)
|
||||
struct lbuf *lbuf;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list ap;
|
||||
int len = 0;
|
||||
char *s;
|
||||
|
||||
#ifdef __STDC__
|
||||
va_start(ap, lbuf);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
while ((s = va_arg(ap, char *)) != NULL)
|
||||
len += strlen(s);
|
||||
va_end(ap);
|
||||
|
||||
/* Expand buffer as needed. */
|
||||
if (lbuf->len + len >= lbuf->size) {
|
||||
do {
|
||||
lbuf->size += 256;
|
||||
} while (lbuf->len + len >= lbuf->size);
|
||||
lbuf->buf = erealloc(lbuf->buf, lbuf->size);
|
||||
}
|
||||
|
||||
#ifdef __STDC__
|
||||
va_start(ap, lbuf);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
/* Append each string. */
|
||||
while ((s = va_arg(ap, char *)) != NULL) {
|
||||
len = strlen(s);
|
||||
memcpy(lbuf->buf + lbuf->len, s, len);
|
||||
lbuf->len += len;
|
||||
}
|
||||
lbuf->buf[lbuf->len] = '\0';
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the buffer with word wrap based on the tty width.
|
||||
* The lbuf is reset on return.
|
||||
*/
|
||||
void
|
||||
lbuf_print(lbuf)
|
||||
struct lbuf *lbuf;
|
||||
{
|
||||
char *cp;
|
||||
int i, have, contlen;
|
||||
static int cols = -1;
|
||||
|
||||
if (cols == -1)
|
||||
cols = get_ttycols();
|
||||
contlen = lbuf->continuation ? 2 : 0;
|
||||
|
||||
/* For very small widths just give up... */
|
||||
if (cols <= lbuf->indent + contlen + 20) {
|
||||
puts(lbuf->buf);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the buffer, splitting the line as needed on a word
|
||||
* boundary.
|
||||
*/
|
||||
cp = lbuf->buf;
|
||||
have = cols;
|
||||
while (cp != NULL && *cp != '\0') {
|
||||
char *ep;
|
||||
int need = lbuf->len - (int)(cp - lbuf->buf);
|
||||
|
||||
ep = memrchr(cp, '\n', need > have ? have : need);
|
||||
if (ep) {
|
||||
need = ep - cp;
|
||||
ep++; /* skip over newline */
|
||||
} else if (need > have) {
|
||||
have -= contlen; /* subtract for continuation char */
|
||||
if ((ep = memrchr(cp, ' ', have)) == NULL)
|
||||
ep = memchr(cp + have, ' ', need - have);
|
||||
if (ep != NULL)
|
||||
need = (int)(ep - cp);
|
||||
}
|
||||
if (cp != lbuf->buf) {
|
||||
/* indent continued lines */
|
||||
for (i = 0; i < lbuf->indent; i++)
|
||||
putchar(' ');
|
||||
}
|
||||
fwrite(cp, need, 1, stdout);
|
||||
cp = ep;
|
||||
|
||||
/*
|
||||
* If there is more to print, reset have, incremement cp past
|
||||
* the whitespace, and print a line continuaton char if needed.
|
||||
*/
|
||||
if (cp != NULL) {
|
||||
have = cols - lbuf->indent;
|
||||
do {
|
||||
cp++;
|
||||
} while (isspace((unsigned char)*cp));
|
||||
if (lbuf->continuation) {
|
||||
putchar(' ');
|
||||
putchar(lbuf->continuation);
|
||||
}
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
done:
|
||||
lbuf->len = 0; /* reset the buffer for re-use. */
|
||||
}
|
133
src/list.c
Normal file
133
src/list.c
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2008 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif /* STDC_HEADERS */
|
||||
|
||||
#include "sudo.h"
|
||||
|
||||
struct list_proto {
|
||||
struct list_proto *prev;
|
||||
struct list_proto *next;
|
||||
};
|
||||
|
||||
struct list_head_proto {
|
||||
struct list_proto *first;
|
||||
struct list_proto *last;
|
||||
};
|
||||
|
||||
/*
|
||||
* Pop the last element off the end of vh.
|
||||
* Returns the popped element.
|
||||
*/
|
||||
void *
|
||||
tq_pop(vh)
|
||||
void *vh;
|
||||
{
|
||||
struct list_head_proto *h = (struct list_head_proto *)vh;
|
||||
void *last = NULL;
|
||||
|
||||
if (!tq_empty(h)) {
|
||||
last = (void *)h->last;
|
||||
if (h->first == h->last) {
|
||||
h->first = NULL;
|
||||
h->last = NULL;
|
||||
} else {
|
||||
h->last = h->last->prev;
|
||||
h->last->next = NULL;
|
||||
}
|
||||
}
|
||||
return (last);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert from a semi-circle queue to normal doubly-linked list
|
||||
* with a head node.
|
||||
*/
|
||||
void
|
||||
list2tq(vh, vl)
|
||||
void *vh;
|
||||
void *vl;
|
||||
{
|
||||
struct list_head_proto *h = (struct list_head_proto *)vh;
|
||||
struct list_proto *l = (struct list_proto *)vl;
|
||||
|
||||
if (l != NULL) {
|
||||
#ifdef DEBUG
|
||||
if (l->prev == NULL) {
|
||||
warningx("list2tq called with non-semicircular list");
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
h->first = l;
|
||||
h->last = l->prev; /* l->prev points to the last member of l */
|
||||
l->prev = NULL; /* zero last ptr now that we have a head */
|
||||
} else {
|
||||
h->first = NULL;
|
||||
h->last = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Append one queue (or single entry) to another using the
|
||||
* circular properties of the prev pointer to simplify the logic.
|
||||
*/
|
||||
void
|
||||
list_append(vl1, vl2)
|
||||
void *vl1;
|
||||
void *vl2;
|
||||
{
|
||||
struct list_proto *l1 = (struct list_proto *)vl1;
|
||||
struct list_proto *l2 = (struct list_proto *)vl2;
|
||||
void *tail = l2->prev;
|
||||
|
||||
l1->prev->next = l2;
|
||||
l2->prev = l1->prev;
|
||||
l1->prev = tail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Append the list of entries to the head node and convert
|
||||
* e from a semi-circle queue to normal doubly-linked list.
|
||||
*/
|
||||
void
|
||||
tq_append(vh, vl)
|
||||
void *vh;
|
||||
void *vl;
|
||||
{
|
||||
struct list_head_proto *h = (struct list_head_proto *)vh;
|
||||
struct list_proto *l = (struct list_proto *)vl;
|
||||
void *tail = l->prev;
|
||||
|
||||
if (h->first == NULL)
|
||||
h->first = l;
|
||||
else
|
||||
h->last->next = l;
|
||||
l->prev = h->last;
|
||||
h->last = tail;
|
||||
}
|
200
src/pty.c
Normal file
200
src/pty.c
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef HAVE_SYS_STROPTS_H
|
||||
#include <sys/stropts.h>
|
||||
#endif /* HAVE_SYS_STROPTS_H */
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif /* STDC_HEADERS */
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif /* HAVE_STRING_H */
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#ifdef HAVE_UTIL_H
|
||||
# include <util.h>
|
||||
#endif
|
||||
#ifdef HAVE_PTY_H
|
||||
# include <pty.h>
|
||||
#endif
|
||||
|
||||
#include "sudo.h"
|
||||
|
||||
#if defined(HAVE_OPENPTY)
|
||||
int
|
||||
get_pty(master, slave, name, namesz)
|
||||
int *master;
|
||||
int *slave;
|
||||
char *name;
|
||||
size_t namesz;
|
||||
{
|
||||
struct group *gr;
|
||||
gid_t ttygid = -1;
|
||||
|
||||
if ((gr = sudo_getgrnam("tty")) != NULL)
|
||||
ttygid = gr->gr_gid;
|
||||
|
||||
if (openpty(master, slave, name, NULL, NULL) != 0)
|
||||
return(0);
|
||||
(void) chown(name, runas_pw->pw_uid, ttygid);
|
||||
return(1);
|
||||
}
|
||||
|
||||
#elif defined(HAVE__GETPTY)
|
||||
int
|
||||
get_pty(master, slave, name, namesz)
|
||||
int *master;
|
||||
int *slave;
|
||||
char *name;
|
||||
size_t namesz;
|
||||
{
|
||||
char *line;
|
||||
|
||||
/* IRIX-style dynamic ptys (may fork) */
|
||||
line = _getpty(master, O_RDWR, IRUSR|S_IWUSR|S_IWGRP, 0);
|
||||
if (line == NULL)
|
||||
return (0);
|
||||
*slave = open(line, O_RDWR|O_NOCTTY, 0);
|
||||
if (*slave == -1) {
|
||||
close(*master);
|
||||
return(0);
|
||||
}
|
||||
(void) chown(line, runas_pw->pw_uid, -1);
|
||||
strlcpy(name, line, namesz);
|
||||
return(1);
|
||||
}
|
||||
#elif defined(HAVE_GRANTPT)
|
||||
# ifndef HAVE_POSIX_OPENPT
|
||||
static int
|
||||
posix_openpt(oflag)
|
||||
int oflag;
|
||||
{
|
||||
int fd;
|
||||
|
||||
# ifdef _AIX
|
||||
fd = open("/dev/ptc", oflag);
|
||||
# else
|
||||
fd = open("/dev/ptmx", oflag);
|
||||
# endif
|
||||
return(fd);
|
||||
}
|
||||
# endif /* HAVE_POSIX_OPENPT */
|
||||
|
||||
int
|
||||
get_pty(master, slave, name, namesz)
|
||||
int *master;
|
||||
int *slave;
|
||||
char *name;
|
||||
size_t namesz;
|
||||
{
|
||||
char *line;
|
||||
|
||||
*master = posix_openpt(O_RDWR|O_NOCTTY);
|
||||
if (*master == -1)
|
||||
return(0);
|
||||
|
||||
(void) grantpt(*master); /* may fork */
|
||||
if (unlockpt(*master) != 0) {
|
||||
close(*master);
|
||||
return(0);
|
||||
}
|
||||
line = ptsname(*master);
|
||||
if (line == NULL) {
|
||||
close(*master);
|
||||
return(0);
|
||||
}
|
||||
*slave = open(line, O_RDWR|O_NOCTTY, 0);
|
||||
if (*slave == -1) {
|
||||
close(*master);
|
||||
return(0);
|
||||
}
|
||||
# ifdef I_PUSH
|
||||
ioctl(*slave, I_PUSH, "ptem"); /* pseudo tty emulation module */
|
||||
ioctl(*slave, I_PUSH, "ldterm"); /* line discipline module */
|
||||
# endif
|
||||
(void) chown(line, runas_pw->pw_uid, -1);
|
||||
strlcpy(name, line, namesz);
|
||||
return(1);
|
||||
}
|
||||
|
||||
#else /* Old-style BSD ptys */
|
||||
|
||||
static char line[] = "/dev/ptyXX";
|
||||
|
||||
int
|
||||
get_pty(master, slave, name, namesz)
|
||||
int *master;
|
||||
int *slave;
|
||||
char *name;
|
||||
size_t namesz;
|
||||
{
|
||||
char *bank, *cp;
|
||||
struct group *gr;
|
||||
gid_t ttygid = -1;
|
||||
|
||||
if ((gr = sudo_getgrnam("tty")) != NULL)
|
||||
ttygid = gr->gr_gid;
|
||||
|
||||
for (bank = "pqrs"; *bank != '\0'; bank++) {
|
||||
line[sizeof("/dev/ptyX") - 2] = *bank;
|
||||
for (cp = "0123456789abcdef"; *cp != '\0'; cp++) {
|
||||
line[sizeof("/dev/ptyXX") - 2] = *cp;
|
||||
*master = open(line, O_RDWR|O_NOCTTY, 0);
|
||||
if (*master == -1) {
|
||||
if (errno == ENOENT)
|
||||
return(0); /* out of ptys */
|
||||
continue; /* already in use */
|
||||
}
|
||||
line[sizeof("/dev/p") - 2] = 't';
|
||||
(void) chown(line, runas_pw->pw_uid, ttygid);
|
||||
(void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP);
|
||||
# ifdef HAVE_REVOKE
|
||||
(void) revoke(line);
|
||||
# endif
|
||||
*slave = open(line, O_RDWR|O_NOCTTY, 0);
|
||||
if (*slave != -1) {
|
||||
strlcpy(name, line, namesz);
|
||||
return(1); /* success */
|
||||
}
|
||||
(void) close(*master);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
#endif /* HAVE_OPENPTY */
|
1130
src/script.c
Normal file
1130
src/script.c
Normal file
File diff suppressed because it is too large
Load Diff
349
src/selinux.c
Normal file
349
src/selinux.c
Normal file
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Dan Walsh <dwalsh@redhat.com>
|
||||
*
|
||||
* Borrowed heavily from newrole source code
|
||||
* Authors:
|
||||
* Anthony Colatrella
|
||||
* Tim Fraser
|
||||
* Steve Grubb <sgrubb@redhat.com>
|
||||
* Darrel Goeddel <DGoeddel@trustedcs.com>
|
||||
* Michael Thompson <mcthomps@us.ibm.com>
|
||||
* Dan Walsh <dwalsh@redhat.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#ifdef WITH_AUDIT
|
||||
#include <libaudit.h>
|
||||
#endif
|
||||
|
||||
#include <selinux/flask.h> /* for SECCLASS_CHR_FILE */
|
||||
#include <selinux/selinux.h> /* for is_selinux_enabled() */
|
||||
#include <selinux/context.h> /* for context-mangling functions */
|
||||
#include <selinux/get_default_type.h>
|
||||
#include <selinux/get_context_list.h>
|
||||
|
||||
#include "sudo.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
static security_context_t old_context;
|
||||
static security_context_t new_context;
|
||||
static security_context_t tty_context;
|
||||
static security_context_t new_tty_context;
|
||||
static int enforcing;
|
||||
|
||||
/*
|
||||
* This function attempts to revert the relabeling done to the tty.
|
||||
* fd - referencing the opened ttyn
|
||||
* ttyn - name of tty to restore
|
||||
* tty_context - original context of the tty
|
||||
* new_tty_context - context tty was relabeled to
|
||||
*
|
||||
* Returns zero on success, non-zero otherwise
|
||||
*/
|
||||
static int
|
||||
restore_tty_label(int fd, const char *ttyn, security_context_t tty_context,
|
||||
security_context_t new_tty_context)
|
||||
{
|
||||
int rc = 0;
|
||||
security_context_t chk_tty_context = NULL;
|
||||
|
||||
if (!ttyn)
|
||||
goto skip_relabel;
|
||||
|
||||
if (!new_tty_context)
|
||||
goto skip_relabel;
|
||||
|
||||
/* Verify that the tty still has the context set by sudo. */
|
||||
if ((rc = fgetfilecon(fd, &chk_tty_context)) < 0) {
|
||||
warning("unable to fgetfilecon %s", ttyn);
|
||||
goto skip_relabel;
|
||||
}
|
||||
|
||||
if ((rc = strcmp(chk_tty_context, new_tty_context))) {
|
||||
warningx("%s changed labels.", ttyn);
|
||||
goto skip_relabel;
|
||||
}
|
||||
|
||||
if ((rc = fsetfilecon(fd, tty_context)) < 0)
|
||||
warning("unable to restore context for %s", ttyn);
|
||||
|
||||
skip_relabel:
|
||||
freecon(chk_tty_context);
|
||||
return(rc);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function attempts to relabel the tty. If this function fails, then
|
||||
* the contexts are free'd and -1 is returned. On success, 0 is returned
|
||||
* and tty_context and new_tty_context are set.
|
||||
*
|
||||
* This function will not fail if it can not relabel the tty when selinux is
|
||||
* in permissive mode.
|
||||
*/
|
||||
static int
|
||||
relabel_tty(int ttyfd, security_context_t new_context,
|
||||
security_context_t *tty_context, security_context_t *new_tty_context,
|
||||
int enforcing)
|
||||
{
|
||||
security_context_t tty_con = NULL;
|
||||
security_context_t new_tty_con = NULL;
|
||||
|
||||
if (fgetfilecon(ttyfd, &tty_con) < 0) {
|
||||
warning("unable to get current tty context, not relabeling tty");
|
||||
if (enforcing)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (tty_con && (security_compute_relabel(new_context, tty_con,
|
||||
SECCLASS_CHR_FILE, &new_tty_con) < 0)) {
|
||||
warning("unable to get new tty context, not relabeling tty");
|
||||
if (enforcing)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (new_tty_con != NULL) {
|
||||
if (fsetfilecon(ttyfd, new_tty_con) < 0) {
|
||||
warning("unable to set new tty context");
|
||||
if (enforcing)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
*tty_context = tty_con;
|
||||
*new_tty_context = new_tty_con;
|
||||
return(0);
|
||||
|
||||
error:
|
||||
freecon(tty_con);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a new security context based on the old context and the
|
||||
* specified role and type.
|
||||
*/
|
||||
security_context_t
|
||||
get_exec_context(security_context_t old_context, char *role, char *type)
|
||||
{
|
||||
security_context_t new_context = NULL;
|
||||
context_t context = NULL;
|
||||
char *typebuf = NULL;
|
||||
|
||||
/* We must have a role, the type is optional (we can use the default). */
|
||||
if (!role) {
|
||||
warningx("you must specify a role.");
|
||||
return(NULL);
|
||||
}
|
||||
if (!type) {
|
||||
if (get_default_type(role, &typebuf)) {
|
||||
warningx("unable to get default type");
|
||||
return(NULL);
|
||||
}
|
||||
type = typebuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand old_context into a context_t so that we extract and modify
|
||||
* its components easily.
|
||||
*/
|
||||
context = context_new(old_context);
|
||||
|
||||
/*
|
||||
* Replace the role and type in "context" with the role and
|
||||
* type we will be running the command as.
|
||||
*/
|
||||
if (context_role_set(context, role)) {
|
||||
warningx("failed to set new role %s", role);
|
||||
goto error;
|
||||
}
|
||||
if (context_type_set(context, type)) {
|
||||
warningx("failed to set new type %s", type);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert "context" back into a string and verify it.
|
||||
*/
|
||||
new_context = estrdup(context_str(context));
|
||||
if (security_check_context(new_context) < 0) {
|
||||
warningx("%s is not a valid context", new_context);
|
||||
goto error;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
warningx("Your new context is %s", new_context);
|
||||
#endif
|
||||
|
||||
context_free(context);
|
||||
return(new_context);
|
||||
|
||||
error:
|
||||
free(typebuf);
|
||||
context_free(context);
|
||||
freecon(new_context);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the tty context in preparation for fork/exec.
|
||||
*/
|
||||
void
|
||||
selinux_prefork(char *role, char *type, int ttyfd)
|
||||
{
|
||||
/* Store the caller's SID in old_context. */
|
||||
if (getprevcon(&old_context))
|
||||
error(EXIT_FAILURE, "failed to get old_context");
|
||||
|
||||
enforcing = security_getenforce();
|
||||
if (enforcing < 0)
|
||||
error(EXIT_FAILURE, "unable to determine enforcing mode.");
|
||||
|
||||
#ifdef DEBUG
|
||||
warningx("your old context was %s", old_context);
|
||||
#endif
|
||||
new_context = get_exec_context(old_context, role, type);
|
||||
if (!new_context)
|
||||
error(EXIT_FAILURE, "unable to get exec context");
|
||||
|
||||
ttyfd = relabel_tty(ttyfd, new_context, &tty_context,
|
||||
&new_tty_context, enforcing);
|
||||
if (ttyfd < 0)
|
||||
error(EXIT_FAILURE, "unable to setup tty context for %s", new_context);
|
||||
|
||||
#ifdef DEBUG
|
||||
warningx("your old tty context is %s", tty_context);
|
||||
warningx("your new tty context is %s", new_tty_context);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
selinux_execv(char *path, char **argv)
|
||||
{
|
||||
if (setexeccon(new_context)) {
|
||||
warning("unable to set exec context to %s", new_context);
|
||||
if (enforcing)
|
||||
return;
|
||||
}
|
||||
|
||||
if (setkeycreatecon(new_context)) {
|
||||
warning("unable to set key creation context to %s", new_context);
|
||||
if (enforcing)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef WITH_AUDIT
|
||||
if (send_audit_message(1, old_context, new_context, user_ttypath))
|
||||
return;
|
||||
#endif
|
||||
|
||||
/* We use the "spare" slot in argv to store sesh. */
|
||||
--argv;
|
||||
argv[0] = *argv[1] == '-' ? "-sesh" : "sesh";
|
||||
argv[1] = path;
|
||||
|
||||
execv(_PATH_SUDO_SESH, argv);
|
||||
warning("%s", path);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the program is being run with a different security context we
|
||||
* need to go through an intermediary process for the transition to
|
||||
* be allowed by the policy. We use the "sesh" shell for this, which
|
||||
* will simply execute the command pass to it on the command line.
|
||||
*/
|
||||
void
|
||||
selinux_exec(char *role, char *type, char **argv)
|
||||
{
|
||||
pid_t childPid;
|
||||
int ttyfd;
|
||||
|
||||
/* Must have a tty. */
|
||||
if (user_ttypath == NULL || *user_ttypath == '\0')
|
||||
error(EXIT_FAILURE, "unable to determine tty");
|
||||
|
||||
/* Re-open TTY descriptor */
|
||||
ttyfd = open(user_ttypath, O_RDWR | O_NONBLOCK);
|
||||
if (ttyfd == -1)
|
||||
error(EXIT_FAILURE, "unable to open %s", user_ttypath);
|
||||
(void)fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NONBLOCK);
|
||||
|
||||
/*
|
||||
* Get the old and new security and tty contexts, sets the new
|
||||
* tty context on ttyfd.
|
||||
*/
|
||||
selinux_prefork(role, type, ttyfd);
|
||||
|
||||
childPid = fork();
|
||||
if (childPid < 0) {
|
||||
/* fork failed, no child to worry about */
|
||||
warning("unable to fork");
|
||||
if (restore_tty_label(ttyfd, user_ttypath, tty_context, new_tty_context))
|
||||
warningx("unable to restore tty label");
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (childPid) {
|
||||
pid_t pid;
|
||||
int status;
|
||||
|
||||
/* Parent, wait for child to finish. */
|
||||
do {
|
||||
pid = waitpid(childPid, &status, 0);
|
||||
} while (pid == -1 && errno == EINTR);
|
||||
|
||||
if (pid == -1)
|
||||
error(EXIT_FAILURE, "waitpid");
|
||||
|
||||
if (restore_tty_label(ttyfd, user_ttypath, tty_context, new_tty_context))
|
||||
errorx(EXIT_FAILURE, "unable to restore tty label");
|
||||
|
||||
/* Preserve child exit status. */
|
||||
if (WIFEXITED(status))
|
||||
exit(WEXITSTATUS(status));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* Child */
|
||||
/* Close the tty and reopen descriptors 0 through 2 */
|
||||
if (close(ttyfd) || close(STDIN_FILENO) || close(STDOUT_FILENO) ||
|
||||
close(STDERR_FILENO)) {
|
||||
warning("could not close descriptors");
|
||||
goto error;
|
||||
}
|
||||
ttyfd = open(user_ttypath, O_RDONLY | O_NONBLOCK);
|
||||
if (ttyfd != STDIN_FILENO)
|
||||
goto error;
|
||||
fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NONBLOCK);
|
||||
ttyfd = open(user_ttypath, O_RDWR | O_NONBLOCK);
|
||||
if (ttyfd != STDOUT_FILENO)
|
||||
goto error;
|
||||
fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NONBLOCK);
|
||||
ttyfd = dup(STDOUT_FILENO);
|
||||
if (ttyfd != STDERR_FILENO)
|
||||
goto error;
|
||||
|
||||
selinux_execv(safe_cmnd, argv);
|
||||
|
||||
error:
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
56
src/sesh.c
Normal file
56
src/sesh.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
char *cp, *cmnd;
|
||||
|
||||
if (argc < 2)
|
||||
errx(EXIT_FAILURE, "requires at least one argument");
|
||||
|
||||
/* Shift argv and make a copy of the command to execute. */
|
||||
argv++;
|
||||
argc--;
|
||||
cmnd = strdup(argv[0]);
|
||||
if (cmnd == NULL)
|
||||
err(EXIT_FAILURE, NULL);
|
||||
|
||||
/* If invoked as a login shell, modify argv[0] accordingly. */
|
||||
if (argv[0][0] == '-') {
|
||||
if ((cp = strrchr(argv[0], '/')) == NULL)
|
||||
cp = argv[0];
|
||||
*cp = '-';
|
||||
}
|
||||
execv(cmnd, argv);
|
||||
warn("unable to execute %s", argv[0]);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
382
src/sudo_edit.c
Normal file
382
src/sudo_edit.c
Normal file
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2008 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif /* STDC_HEADERS */
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif /* HAVE_STRING_H */
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
#include <ctype.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#if TIME_WITH_SYS_TIME
|
||||
# include <time.h>
|
||||
#endif
|
||||
#ifndef HAVE_TIMESPEC
|
||||
# include <emul/timespec.h>
|
||||
#endif
|
||||
|
||||
#include "sudo.h"
|
||||
|
||||
extern sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp;
|
||||
extern char **environ;
|
||||
|
||||
static char *find_editor();
|
||||
|
||||
/*
|
||||
* Wrapper to allow users to edit privileged files with their own uid.
|
||||
*/
|
||||
int
|
||||
sudo_edit(argc, argv, envp)
|
||||
int argc;
|
||||
char **argv;
|
||||
char **envp;
|
||||
{
|
||||
ssize_t nread, nwritten;
|
||||
pid_t kidpid, pid;
|
||||
const char *tmpdir;
|
||||
char **nargv, **ap, *editor, *cp;
|
||||
char buf[BUFSIZ];
|
||||
int error, i, ac, ofd, tfd, nargc, rval, tmplen, wasblank;
|
||||
struct stat sb;
|
||||
struct timespec ts1, ts2;
|
||||
struct tempfile {
|
||||
char *tfile;
|
||||
char *ofile;
|
||||
struct timespec omtim;
|
||||
off_t osize;
|
||||
} *tf;
|
||||
|
||||
/*
|
||||
* Find our temporary directory, one of /var/tmp, /usr/tmp, or /tmp
|
||||
*/
|
||||
if (stat(_PATH_VARTMP, &sb) == 0 && S_ISDIR(sb.st_mode))
|
||||
tmpdir = _PATH_VARTMP;
|
||||
#ifdef _PATH_USRTMP
|
||||
else if (stat(_PATH_USRTMP, &sb) == 0 && S_ISDIR(sb.st_mode))
|
||||
tmpdir = _PATH_USRTMP;
|
||||
#endif
|
||||
else
|
||||
tmpdir = _PATH_TMP;
|
||||
tmplen = strlen(tmpdir);
|
||||
while (tmplen > 0 && tmpdir[tmplen - 1] == '/')
|
||||
tmplen--;
|
||||
|
||||
/*
|
||||
* Close password, shadow, and group files before we try to open
|
||||
* user-specified files to prevent the opening of things like /dev/fd/4
|
||||
*/
|
||||
sudo_endpwent();
|
||||
sudo_endgrent();
|
||||
|
||||
/*
|
||||
* For each file specified by the user, make a temporary version
|
||||
* and copy the contents of the original to it.
|
||||
*/
|
||||
tf = emalloc2(argc - 1, sizeof(*tf));
|
||||
zero_bytes(tf, (argc - 1) * sizeof(*tf));
|
||||
for (i = 0, ap = argv + 1; i < argc - 1 && *ap != NULL; i++, ap++) {
|
||||
error = -1;
|
||||
set_perms(PERM_RUNAS);
|
||||
if ((ofd = open(*ap, O_RDONLY, 0644)) != -1 || errno == ENOENT) {
|
||||
if (ofd == -1) {
|
||||
zero_bytes(&sb, sizeof(sb)); /* new file */
|
||||
error = 0;
|
||||
} else {
|
||||
#ifdef HAVE_FSTAT
|
||||
error = fstat(ofd, &sb);
|
||||
#else
|
||||
error = stat(tf[i].ofile, &sb);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
set_perms(PERM_ROOT);
|
||||
if (error || (ofd != -1 && !S_ISREG(sb.st_mode))) {
|
||||
if (error)
|
||||
warning("%s", *ap);
|
||||
else
|
||||
warningx("%s: not a regular file", *ap);
|
||||
if (ofd != -1)
|
||||
close(ofd);
|
||||
argc--;
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
tf[i].ofile = *ap;
|
||||
tf[i].omtim.tv_sec = mtim_getsec(sb);
|
||||
tf[i].omtim.tv_nsec = mtim_getnsec(sb);
|
||||
tf[i].osize = sb.st_size;
|
||||
if ((cp = strrchr(tf[i].ofile, '/')) != NULL)
|
||||
cp++;
|
||||
else
|
||||
cp = tf[i].ofile;
|
||||
easprintf(&tf[i].tfile, "%.*s/%s.XXXXXXXX", tmplen, tmpdir, cp);
|
||||
set_perms(PERM_USER);
|
||||
tfd = mkstemp(tf[i].tfile);
|
||||
set_perms(PERM_ROOT);
|
||||
if (tfd == -1) {
|
||||
warning("mkstemp");
|
||||
goto cleanup;
|
||||
}
|
||||
if (ofd != -1) {
|
||||
while ((nread = read(ofd, buf, sizeof(buf))) != 0) {
|
||||
if ((nwritten = write(tfd, buf, nread)) != nread) {
|
||||
if (nwritten == -1)
|
||||
warning("%s", tf[i].tfile);
|
||||
else
|
||||
warningx("%s: short write", tf[i].tfile);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
close(ofd);
|
||||
}
|
||||
/*
|
||||
* We always update the stashed mtime because the time
|
||||
* resolution of the filesystem the temporary file is on may
|
||||
* not match that of the filesystem where the file to be edited
|
||||
* resides. It is OK if touch() fails since we only use the info
|
||||
* to determine whether or not a file has been modified.
|
||||
*/
|
||||
(void) touch(tfd, NULL, &tf[i].omtim);
|
||||
#ifdef HAVE_FSTAT
|
||||
error = fstat(tfd, &sb);
|
||||
#else
|
||||
error = stat(tf[i].tfile, &sb);
|
||||
#endif
|
||||
if (!error) {
|
||||
tf[i].omtim.tv_sec = mtim_getsec(sb);
|
||||
tf[i].omtim.tv_nsec = mtim_getnsec(sb);
|
||||
}
|
||||
close(tfd);
|
||||
}
|
||||
if (argc == 1)
|
||||
return(1); /* no files readable, you lose */
|
||||
|
||||
environ = envp;
|
||||
editor = find_editor();
|
||||
|
||||
/*
|
||||
* Allocate space for the new argument vector and fill it in.
|
||||
* The EDITOR and VISUAL environment variables may contain command
|
||||
* line args so look for those and alloc space for them too.
|
||||
*/
|
||||
nargc = argc;
|
||||
for (wasblank = FALSE, cp = editor; *cp != '\0'; cp++) {
|
||||
if (isblank((unsigned char) *cp))
|
||||
wasblank = TRUE;
|
||||
else if (wasblank) {
|
||||
wasblank = FALSE;
|
||||
nargc++;
|
||||
}
|
||||
}
|
||||
nargv = (char **) emalloc2(nargc + 1, sizeof(char *));
|
||||
ac = 0;
|
||||
for ((cp = strtok(editor, " \t")); cp != NULL; (cp = strtok(NULL, " \t")))
|
||||
nargv[ac++] = cp;
|
||||
for (i = 0; i < argc - 1 && ac < nargc; )
|
||||
nargv[ac++] = tf[i++].tfile;
|
||||
nargv[ac] = NULL;
|
||||
|
||||
/* Allow the editor to be suspended. */
|
||||
(void) sigaction(SIGTSTP, &saved_sa_tstp, NULL);
|
||||
|
||||
/*
|
||||
* Fork and exec the editor with the invoking user's creds,
|
||||
* keeping track of the time spent in the editor.
|
||||
*/
|
||||
gettime(&ts1);
|
||||
kidpid = fork();
|
||||
if (kidpid == -1) {
|
||||
warning("fork");
|
||||
goto cleanup;
|
||||
} else if (kidpid == 0) {
|
||||
/* child */
|
||||
(void) sigaction(SIGINT, &saved_sa_int, NULL);
|
||||
(void) sigaction(SIGQUIT, &saved_sa_quit, NULL);
|
||||
set_perms(PERM_FULL_USER);
|
||||
closefrom(def_closefrom);
|
||||
execvp(nargv[0], nargv);
|
||||
warning("unable to execute %s", nargv[0]);
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for status from the child. Most modern kernels
|
||||
* will not let an unprivileged child process send a
|
||||
* signal to its privileged parent so we have to request
|
||||
* status when the child is stopped and then send the
|
||||
* same signal to our own pid.
|
||||
*/
|
||||
do {
|
||||
#ifdef sudo_waitpid
|
||||
pid = sudo_waitpid(kidpid, &i, WUNTRACED);
|
||||
#else
|
||||
pid = wait(&i);
|
||||
#endif
|
||||
if (pid == kidpid) {
|
||||
if (WIFSTOPPED(i))
|
||||
kill(getpid(), WSTOPSIG(i));
|
||||
else
|
||||
break;
|
||||
}
|
||||
} while (pid != -1 || errno == EINTR);
|
||||
gettime(&ts2);
|
||||
if (pid == -1 || !WIFEXITED(i))
|
||||
rval = 1;
|
||||
else
|
||||
rval = WEXITSTATUS(i);
|
||||
|
||||
/* Copy contents of temp files to real ones */
|
||||
for (i = 0; i < argc - 1; i++) {
|
||||
error = -1;
|
||||
set_perms(PERM_USER);
|
||||
if ((tfd = open(tf[i].tfile, O_RDONLY, 0644)) != -1) {
|
||||
#ifdef HAVE_FSTAT
|
||||
error = fstat(tfd, &sb);
|
||||
#else
|
||||
error = stat(tf[i].tfile, &sb);
|
||||
#endif
|
||||
}
|
||||
set_perms(PERM_ROOT);
|
||||
if (error || !S_ISREG(sb.st_mode)) {
|
||||
if (error)
|
||||
warning("%s", tf[i].tfile);
|
||||
else
|
||||
warningx("%s: not a regular file", tf[i].tfile);
|
||||
warningx("%s left unmodified", tf[i].ofile);
|
||||
if (tfd != -1)
|
||||
close(tfd);
|
||||
continue;
|
||||
}
|
||||
if (tf[i].osize == sb.st_size && tf[i].omtim.tv_sec == mtim_getsec(sb)
|
||||
&& tf[i].omtim.tv_nsec == mtim_getnsec(sb)) {
|
||||
/*
|
||||
* If mtime and size match but the user spent no measurable
|
||||
* time in the editor we can't tell if the file was changed.
|
||||
*/
|
||||
#ifdef HAVE_TIMESPECSUB2
|
||||
timespecsub(&ts1, &ts2);
|
||||
#else
|
||||
timespecsub(&ts1, &ts2, &ts2);
|
||||
#endif
|
||||
if (timespecisset(&ts2)) {
|
||||
warningx("%s unchanged", tf[i].ofile);
|
||||
unlink(tf[i].tfile);
|
||||
close(tfd);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
set_perms(PERM_RUNAS);
|
||||
ofd = open(tf[i].ofile, O_WRONLY|O_TRUNC|O_CREAT, 0644);
|
||||
set_perms(PERM_ROOT);
|
||||
if (ofd == -1) {
|
||||
warning("unable to write to %s", tf[i].ofile);
|
||||
warningx("contents of edit session left in %s", tf[i].tfile);
|
||||
close(tfd);
|
||||
continue;
|
||||
}
|
||||
while ((nread = read(tfd, buf, sizeof(buf))) > 0) {
|
||||
if ((nwritten = write(ofd, buf, nread)) != nread) {
|
||||
if (nwritten == -1)
|
||||
warning("%s", tf[i].ofile);
|
||||
else
|
||||
warningx("%s: short write", tf[i].ofile);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nread == 0) {
|
||||
/* success, got EOF */
|
||||
unlink(tf[i].tfile);
|
||||
} else if (nread < 0) {
|
||||
warning("unable to read temporary file");
|
||||
warningx("contents of edit session left in %s", tf[i].tfile);
|
||||
} else {
|
||||
warning("unable to write to %s", tf[i].ofile);
|
||||
warningx("contents of edit session left in %s", tf[i].tfile);
|
||||
}
|
||||
close(ofd);
|
||||
}
|
||||
|
||||
return(rval);
|
||||
cleanup:
|
||||
/* Clean up temp files and return. */
|
||||
for (i = 0; i < argc - 1; i++) {
|
||||
if (tf[i].tfile != NULL)
|
||||
unlink(tf[i].tfile);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine which editor to use. We don't bother restricting this
|
||||
* based on def_env_editor or def_editor since the editor runs with
|
||||
* the uid of the invoking user, not the runas (privileged) user.
|
||||
*/
|
||||
static char *
|
||||
find_editor()
|
||||
{
|
||||
char *cp, *editor = NULL, **ev, *ev0[4];
|
||||
|
||||
ev0[0] = "SUDO_EDITOR";
|
||||
ev0[1] = "VISUAL";
|
||||
ev0[2] = "EDITOR";
|
||||
ev0[3] = NULL;
|
||||
for (ev = ev0; *ev != NULL; ev++) {
|
||||
if ((editor = getenv(*ev)) != NULL && *editor != '\0') {
|
||||
if ((cp = strrchr(editor, '/')) != NULL)
|
||||
cp++;
|
||||
else
|
||||
cp = editor;
|
||||
/* Ignore "sudoedit" and "sudo" to avoid an endless loop. */
|
||||
if (strncmp(cp, "sudo", 4) != 0 ||
|
||||
(cp[4] != ' ' && cp[4] != '\0' && strcmp(cp + 4, "edit") != 0)) {
|
||||
editor = estrdup(editor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
editor = NULL;
|
||||
}
|
||||
if (editor == NULL) {
|
||||
editor = estrdup(def_editor);
|
||||
if ((cp = strchr(editor, ':')) != NULL)
|
||||
*cp = '\0'; /* def_editor could be a path */
|
||||
}
|
||||
return(editor);
|
||||
}
|
111
src/sudo_noexec.c
Normal file
111
src/sudo_noexec.c
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <errno.h>
|
||||
#ifndef HAVE_TIMESPEC
|
||||
# include <time.h>
|
||||
#endif
|
||||
#ifdef __STDC__
|
||||
# include <stdarg.h>
|
||||
#else
|
||||
# include <varargs.h>
|
||||
#endif
|
||||
|
||||
#include <compat.h>
|
||||
|
||||
/*
|
||||
* Dummy versions of the execve() family of syscalls. We don't need
|
||||
* to stub out all of them, just the ones that correspond to actual
|
||||
* system calls (which varies by OS). Note that it is still possible
|
||||
* to access the real syscalls via the syscall() interface but very
|
||||
* few programs actually do that.
|
||||
*/
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#define DUMMY_BODY \
|
||||
{ \
|
||||
errno = EACCES; \
|
||||
return(-1); \
|
||||
}
|
||||
|
||||
#ifdef __STDC__
|
||||
|
||||
#define DUMMY2(fn, t1, t2) \
|
||||
int \
|
||||
fn(t1 a1, t2 a2) \
|
||||
DUMMY_BODY
|
||||
|
||||
#define DUMMY3(fn, t1, t2, t3) \
|
||||
int \
|
||||
fn(t1 a1, t2 a2, t3 a3) \
|
||||
DUMMY_BODY
|
||||
|
||||
#define DUMMY_VA(fn, t1, t2) \
|
||||
int \
|
||||
fn(t1 a1, t2 a2, ...) \
|
||||
DUMMY_BODY
|
||||
|
||||
#else /* !__STDC__ */
|
||||
|
||||
#define DUMMY2(fn, t1, t2) \
|
||||
int \
|
||||
fn(a1, a2) \
|
||||
t1 a1; t2 a2; \
|
||||
DUMMY_BODY
|
||||
|
||||
#define DUMMY3(fn, t1, t2, t3) \
|
||||
int \
|
||||
fn(a1, a2, a3) \
|
||||
t1 a1; t2 a2; t3 a3; \
|
||||
DUMMY_BODY
|
||||
|
||||
#define DUMMY_VA(fn, t1, t2) \
|
||||
int \
|
||||
fn(a1, a2, va_alist) \
|
||||
t1 a1; t2 a2; va_dcl \
|
||||
DUMMY_BODY
|
||||
|
||||
#endif /* !__STDC__ */
|
||||
|
||||
DUMMY_VA(execl, const char *, const char *)
|
||||
DUMMY_VA(_execl, const char *, const char *)
|
||||
DUMMY_VA(__execl, const char *, const char *)
|
||||
DUMMY_VA(execle, const char *, const char *)
|
||||
DUMMY_VA(_execle, const char *, const char *)
|
||||
DUMMY_VA(__execle, const char *, const char *)
|
||||
DUMMY_VA(execlp, const char *, const char *)
|
||||
DUMMY_VA(_execlp, const char *, const char *)
|
||||
DUMMY_VA(__execlp, const char *, const char *)
|
||||
DUMMY2(execv, const char *, char * const *)
|
||||
DUMMY2(_execv, const char *, char * const *)
|
||||
DUMMY2(__execv, const char *, char * const *)
|
||||
DUMMY2(execvp, const char *, char * const *)
|
||||
DUMMY2(_execvp, const char *, char * const *)
|
||||
DUMMY2(__execvp, const char *, char * const *)
|
||||
DUMMY3(execvP, const char *, const char *, char * const *)
|
||||
DUMMY3(_execvP, const char *, const char *, char * const *)
|
||||
DUMMY3(__execvP, const char *, const char *, char * const *)
|
||||
DUMMY3(execve, const char *, char * const *, char * const *)
|
||||
DUMMY3(_execve, const char *, char * const *, char * const *)
|
||||
DUMMY3(__execve, const char *, char * const *, char * const *)
|
||||
DUMMY3(fexecve, int , char * const *, char * const *)
|
||||
DUMMY3(_fexecve, int , char * const *, char * const *)
|
||||
DUMMY3(__fexecve, int , char * const *, char * const *)
|
282
src/term.c
Normal file
282
src/term.c
Normal file
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif /* STDC_HEADERS */
|
||||
#ifdef HAVE_STRING_H
|
||||
# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
|
||||
# include <memory.h>
|
||||
# endif
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif /* HAVE_STRING_H */
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
# include <termios.h>
|
||||
#else
|
||||
# ifdef HAVE_TERMIO_H
|
||||
# include <termio.h>
|
||||
# else
|
||||
# include <sgtty.h>
|
||||
# include <sys/ioctl.h>
|
||||
# endif /* HAVE_TERMIO_H */
|
||||
#endif /* HAVE_TERMIOS_H */
|
||||
|
||||
#include "sudo.h"
|
||||
|
||||
#ifndef TCSASOFT
|
||||
# define TCSASOFT 0
|
||||
#endif
|
||||
#ifndef ECHONL
|
||||
# define ECHONL 0
|
||||
#endif
|
||||
#ifndef IEXTEN
|
||||
# define IEXTEN 0
|
||||
#endif
|
||||
#ifndef IUCLC
|
||||
# define IUCLC 0
|
||||
#endif
|
||||
|
||||
#ifndef _POSIX_VDISABLE
|
||||
# ifdef VDISABLE
|
||||
# define _POSIX_VDISABLE VDISABLE
|
||||
# else
|
||||
# define _POSIX_VDISABLE 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compat macros for non-termios systems.
|
||||
*/
|
||||
#ifndef HAVE_TERMIOS_H
|
||||
# ifdef HAVE_TERMIO_H
|
||||
# undef termios
|
||||
# define termios termio
|
||||
# define tcgetattr(f, t) ioctl(f, TCGETA, t)
|
||||
# define tcsetattr(f, a, t) ioctl(f, a, t)
|
||||
# undef TCSAFLUSH
|
||||
# define TCSAFLUSH TCSETAF
|
||||
# undef TCSADRAIN
|
||||
# define TCSADRAIN TCSETAW
|
||||
# else /* SGTTY */
|
||||
# undef termios
|
||||
# define termios sgttyb
|
||||
# define c_lflag sg_flags
|
||||
# define tcgetattr(f, t) ioctl(f, TIOCGETP, t)
|
||||
# define tcsetattr(f, a, t) ioctl(f, a, t)
|
||||
# undef TCSAFLUSH
|
||||
# define TCSAFLUSH TIOCSETP
|
||||
# undef TCSADRAIN
|
||||
# define TCSADRAIN TIOCSETN
|
||||
# endif /* HAVE_TERMIO_H */
|
||||
#endif /* HAVE_TERMIOS_H */
|
||||
|
||||
typedef struct termios sudo_term_t;
|
||||
|
||||
static sudo_term_t term, oterm;
|
||||
static int changed;
|
||||
int term_erase;
|
||||
int term_kill;
|
||||
|
||||
int
|
||||
term_restore(fd, flush)
|
||||
int fd;
|
||||
int flush;
|
||||
{
|
||||
if (changed) {
|
||||
int flags = TCSASOFT;
|
||||
flags |= flush ? TCSAFLUSH : TCSADRAIN;
|
||||
if (tcsetattr(fd, flags, &oterm) != 0)
|
||||
return(0);
|
||||
changed = 0;
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
int
|
||||
term_noecho(fd)
|
||||
int fd;
|
||||
{
|
||||
if (!changed && tcgetattr(fd, &oterm) != 0)
|
||||
return(0);
|
||||
(void) memcpy(&term, &oterm, sizeof(term));
|
||||
CLR(term.c_lflag, ECHO|ECHONL);
|
||||
#ifdef VSTATUS
|
||||
term.c_cc[VSTATUS] = _POSIX_VDISABLE;
|
||||
#endif
|
||||
if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) {
|
||||
changed = 1;
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
#if defined(HAVE_TERMIOS_H) || defined(HAVE_TERMIO_H)
|
||||
|
||||
int
|
||||
term_raw(fd, opost, isig)
|
||||
int fd;
|
||||
int opost;
|
||||
int isig;
|
||||
{
|
||||
struct termios term;
|
||||
|
||||
if (!changed && tcgetattr(fd, &oterm) != 0)
|
||||
return(0);
|
||||
(void) memcpy(&term, &oterm, sizeof(term));
|
||||
/* Set terminal to raw mode */
|
||||
term.c_cc[VMIN] = 1;
|
||||
term.c_cc[VTIME] = 0;
|
||||
CLR(term.c_lflag, ECHO | ECHONL | ICANON | ISIG | IEXTEN);
|
||||
if (isig)
|
||||
SET(term.c_lflag, ISIG);
|
||||
CLR(term.c_iflag, ICRNL | IGNCR | INLCR | IUCLC | IXON);
|
||||
/* Only retain output post-processing opost flag set. */
|
||||
if (!opost)
|
||||
CLR(term.c_oflag, OPOST);
|
||||
if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) {
|
||||
changed = 1;
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
term_cbreak(fd)
|
||||
int fd;
|
||||
{
|
||||
if (!changed && tcgetattr(fd, &oterm) != 0)
|
||||
return(0);
|
||||
(void) memcpy(&term, &oterm, sizeof(term));
|
||||
/* Set terminal to half-cooked mode */
|
||||
term.c_cc[VMIN] = 1;
|
||||
term.c_cc[VTIME] = 0;
|
||||
CLR(term.c_lflag, ECHO | ECHONL | ICANON | IEXTEN);
|
||||
SET(term.c_lflag, ISIG);
|
||||
#ifdef VSTATUS
|
||||
term.c_cc[VSTATUS] = _POSIX_VDISABLE;
|
||||
#endif
|
||||
if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) {
|
||||
term_erase = term.c_cc[VERASE];
|
||||
term_kill = term.c_cc[VKILL];
|
||||
changed = 1;
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
term_copy(src, dst, opost)
|
||||
int src;
|
||||
int dst;
|
||||
int opost;
|
||||
{
|
||||
struct termios tt;
|
||||
|
||||
if (tcgetattr(src, &tt) != 0)
|
||||
return(0);
|
||||
/* Do not do post-processing unless opost set. */
|
||||
if (!opost)
|
||||
CLR(tt.c_oflag, OPOST);
|
||||
/* XXX - add TCSANOW compat define */
|
||||
if (tcsetattr(dst, TCSANOW|TCSASOFT, &tt) != 0)
|
||||
return(0);
|
||||
return(1);
|
||||
}
|
||||
|
||||
#else /* SGTTY */
|
||||
|
||||
int
|
||||
term_raw(fd, onlcr)
|
||||
int fd;
|
||||
int onlcr;
|
||||
{
|
||||
if (!changed && ioctl(fd, TIOCGETP, &oterm) != 0)
|
||||
return(0);
|
||||
(void) memcpy(&term, &oterm, sizeof(term));
|
||||
/* Set terminal to raw mode */
|
||||
CLR(term.c_lflag, ECHO);
|
||||
SET(term.sg_flags, RAW);
|
||||
/* Retain NL to NLCR conversion if onlcr flag set. */
|
||||
if (onlcr)
|
||||
SET(term.sg_flags, CRMOD);
|
||||
if (ioctl(fd, TIOCSETP, &term) == 0) {
|
||||
changed = 1;
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
term_cbreak(fd)
|
||||
int fd;
|
||||
{
|
||||
if (!changed && ioctl(fd, TIOCGETP, &oterm) != 0)
|
||||
return(0);
|
||||
(void) memcpy(&term, &oterm, sizeof(term));
|
||||
/* Set terminal to half-cooked mode */
|
||||
CLR(term.c_lflag, ECHO);
|
||||
SET(term.sg_flags, CBREAK);
|
||||
if (ioctl(fd, TIOCSETP, &term) == 0) {
|
||||
term_erase = term.sg_erase;
|
||||
term_kill = term.sg_kill;
|
||||
changed = 1;
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
term_copy(src, dst, onlcr)
|
||||
int src;
|
||||
int dst;
|
||||
int onlcr;
|
||||
{
|
||||
struct sgttyb b;
|
||||
struct tchars tc;
|
||||
struct ltchars lc;
|
||||
int l, lb;
|
||||
|
||||
if (ioctl(src, TIOCGETP, &b) != 0 || ioctl(src, TIOCGETC, &tc) != 0 ||
|
||||
ioctl(src, TIOCGETD, &l) != 0 || ioctl(src, TIOCGLTC, &lc) != 0 ||
|
||||
ioctl(src, TIOCLGET, &lb)) {
|
||||
return(0);
|
||||
}
|
||||
/* Do not convert line endings from NL to NLCR. */
|
||||
if (!onlcr)
|
||||
CLR(b.sg_flags, CRMOD);
|
||||
if (ioctl(dst, TIOCSETP, &b) != 0 || ioctl(dst, TIOCSETC, &tc) != 0 ||
|
||||
ioctl(dst, TIOCSLTC, &lc) != 0 || ioctl(dst, TIOCLSET, &lb) != 0 ||
|
||||
ioctl(dst, TIOCSETD, &l) != 0) {
|
||||
return(0);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
#endif
|
281
src/tgetpass.c
Normal file
281
src/tgetpass.c
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 1998-2005, 2007-2009
|
||||
* Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Sponsored in part by the Defense Advanced Research Projects
|
||||
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||
*/
|
||||
|
||||
#ifdef __TANDEM
|
||||
# include <floss.h>
|
||||
#endif
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif /* STDC_HEADERS */
|
||||
#ifdef HAVE_STRING_H
|
||||
# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
|
||||
# include <memory.h>
|
||||
# endif
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif /* HAVE_STRING_H */
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
#include <pwd.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "sudo.h"
|
||||
|
||||
static volatile sig_atomic_t signo;
|
||||
|
||||
static void handler __P((int));
|
||||
static char *getln __P((int, char *, size_t, int));
|
||||
static char *sudo_askpass __P((const char *));
|
||||
|
||||
/*
|
||||
* Like getpass(3) but with timeout and echo flags.
|
||||
*/
|
||||
char *
|
||||
tgetpass(prompt, timeout, flags)
|
||||
const char *prompt;
|
||||
int timeout;
|
||||
int flags;
|
||||
{
|
||||
sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm;
|
||||
sigaction_t savetstp, savettin, savettou;
|
||||
char *pass;
|
||||
static char buf[SUDO_PASS_MAX + 1];
|
||||
int input, output, save_errno, neednl;;
|
||||
|
||||
(void) fflush(stdout);
|
||||
|
||||
/* If using a helper program to get the password, run it instead. */
|
||||
if (ISSET(flags, TGP_ASKPASS) && user_askpass)
|
||||
return(sudo_askpass(prompt));
|
||||
|
||||
restart:
|
||||
signo = 0;
|
||||
pass = NULL;
|
||||
save_errno = 0;
|
||||
/* Open /dev/tty for reading/writing if possible else use stdin/stderr. */
|
||||
if (ISSET(flags, TGP_STDIN) ||
|
||||
(input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
|
||||
input = STDIN_FILENO;
|
||||
output = STDERR_FILENO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Catch signals that would otherwise cause the user to end
|
||||
* up with echo turned off in the shell.
|
||||
*/
|
||||
zero_bytes(&sa, sizeof(sa));
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_INTERRUPT; /* don't restart system calls */
|
||||
sa.sa_handler = handler;
|
||||
(void) sigaction(SIGALRM, &sa, &savealrm);
|
||||
(void) sigaction(SIGINT, &sa, &saveint);
|
||||
(void) sigaction(SIGHUP, &sa, &savehup);
|
||||
(void) sigaction(SIGQUIT, &sa, &savequit);
|
||||
(void) sigaction(SIGTERM, &sa, &saveterm);
|
||||
(void) sigaction(SIGTSTP, &sa, &savetstp);
|
||||
(void) sigaction(SIGTTIN, &sa, &savettin);
|
||||
(void) sigaction(SIGTTOU, &sa, &savettou);
|
||||
|
||||
if (def_pwfeedback)
|
||||
neednl = term_cbreak(input);
|
||||
else
|
||||
neednl = term_noecho(input);
|
||||
|
||||
/* No output if we are already backgrounded. */
|
||||
if (signo != SIGTTOU && signo != SIGTTIN) {
|
||||
if (prompt)
|
||||
(void) write(output, prompt, strlen(prompt));
|
||||
|
||||
if (timeout > 0)
|
||||
alarm(timeout);
|
||||
pass = getln(input, buf, sizeof(buf), def_pwfeedback);
|
||||
alarm(0);
|
||||
save_errno = errno;
|
||||
|
||||
if (neednl)
|
||||
(void) write(output, "\n", 1);
|
||||
}
|
||||
|
||||
/* Restore old tty settings and signals. */
|
||||
term_restore(input, 1);
|
||||
(void) sigaction(SIGALRM, &savealrm, NULL);
|
||||
(void) sigaction(SIGINT, &saveint, NULL);
|
||||
(void) sigaction(SIGHUP, &savehup, NULL);
|
||||
(void) sigaction(SIGQUIT, &savequit, NULL);
|
||||
(void) sigaction(SIGTERM, &saveterm, NULL);
|
||||
(void) sigaction(SIGTSTP, &savetstp, NULL);
|
||||
(void) sigaction(SIGTTIN, &savettin, NULL);
|
||||
(void) sigaction(SIGTTOU, &savettou, NULL);
|
||||
if (input != STDIN_FILENO)
|
||||
(void) close(input);
|
||||
|
||||
/*
|
||||
* If we were interrupted by a signal, resend it to ourselves
|
||||
* now that we have restored the signal handlers.
|
||||
*/
|
||||
if (signo) {
|
||||
kill(getpid(), signo);
|
||||
switch (signo) {
|
||||
case SIGTSTP:
|
||||
case SIGTTIN:
|
||||
case SIGTTOU:
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
|
||||
if (save_errno)
|
||||
errno = save_errno;
|
||||
return(pass);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fork a child and exec sudo-askpass to get the password from the user.
|
||||
*/
|
||||
static char *
|
||||
sudo_askpass(prompt)
|
||||
const char *prompt;
|
||||
{
|
||||
static char buf[SUDO_PASS_MAX + 1], *pass;
|
||||
sigaction_t sa, saved_sa_pipe;
|
||||
int pfd[2];
|
||||
pid_t pid;
|
||||
|
||||
if (pipe(pfd) == -1)
|
||||
error(1, "unable to create pipe");
|
||||
|
||||
if ((pid = fork()) == -1)
|
||||
error(1, "unable to fork");
|
||||
|
||||
if (pid == 0) {
|
||||
/* child, point stdout to output side of the pipe and exec askpass */
|
||||
(void) dup2(pfd[1], STDOUT_FILENO);
|
||||
set_perms(PERM_FULL_USER);
|
||||
closefrom(STDERR_FILENO + 1);
|
||||
execl(user_askpass, user_askpass, prompt, (char *)NULL);
|
||||
warning("unable to run %s", user_askpass);
|
||||
_exit(255);
|
||||
}
|
||||
|
||||
/* Ignore SIGPIPE in case child exits prematurely */
|
||||
zero_bytes(&sa, sizeof(sa));
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
sa.sa_handler = SIG_IGN;
|
||||
(void) sigaction(SIGPIPE, &sa, &saved_sa_pipe);
|
||||
|
||||
/* Get response from child (askpass) and restore SIGPIPE handler */
|
||||
(void) close(pfd[1]);
|
||||
pass = getln(pfd[0], buf, sizeof(buf), 0);
|
||||
(void) close(pfd[0]);
|
||||
(void) sigaction(SIGPIPE, &saved_sa_pipe, NULL);
|
||||
|
||||
return(pass);
|
||||
}
|
||||
|
||||
extern int term_erase, term_kill;
|
||||
|
||||
static char *
|
||||
getln(fd, buf, bufsiz, feedback)
|
||||
int fd;
|
||||
char *buf;
|
||||
size_t bufsiz;
|
||||
int feedback;
|
||||
{
|
||||
size_t left = bufsiz;
|
||||
ssize_t nr = -1;
|
||||
char *cp = buf;
|
||||
char c = '\0';
|
||||
|
||||
if (left == 0) {
|
||||
errno = EINVAL;
|
||||
return(NULL); /* sanity */
|
||||
}
|
||||
|
||||
while (--left) {
|
||||
nr = read(fd, &c, 1);
|
||||
if (nr != 1 || c == '\n' || c == '\r')
|
||||
break;
|
||||
if (feedback) {
|
||||
if (c == term_kill) {
|
||||
while (cp > buf) {
|
||||
(void) write(fd, "\b \b", 3);
|
||||
--cp;
|
||||
}
|
||||
left = bufsiz;
|
||||
continue;
|
||||
} else if (c == term_erase) {
|
||||
if (cp > buf) {
|
||||
(void) write(fd, "\b \b", 3);
|
||||
--cp;
|
||||
left++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
(void) write(fd, "*", 1);
|
||||
}
|
||||
*cp++ = c;
|
||||
}
|
||||
*cp = '\0';
|
||||
if (feedback) {
|
||||
/* erase stars */
|
||||
while (cp > buf) {
|
||||
(void) write(fd, "\b \b", 3);
|
||||
--cp;
|
||||
}
|
||||
}
|
||||
|
||||
return(nr == 1 ? buf : NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
handler(s)
|
||||
int s;
|
||||
{
|
||||
if (s != SIGALRM)
|
||||
signo = s;
|
||||
}
|
||||
|
||||
int
|
||||
tty_present()
|
||||
{
|
||||
int fd;
|
||||
|
||||
if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) != -1)
|
||||
close(fd);
|
||||
return(fd != -1);
|
||||
}
|
36
src/zero_bytes.c
Normal file
36
src/zero_bytes.c
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2003-2005, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <config.h>
|
||||
#include <compat.h>
|
||||
|
||||
/*
|
||||
* Like bzero(3) but with a volatile pointer. The hope is that
|
||||
* the compiler will not be able to optimize away this function.
|
||||
*/
|
||||
void
|
||||
zero_bytes(v, n)
|
||||
volatile void *v;
|
||||
size_t n;
|
||||
{
|
||||
volatile char *p, *ep;
|
||||
|
||||
for (p = v, ep = p + n; p < ep; p++)
|
||||
*p = 0;
|
||||
return;
|
||||
}
|
Reference in New Issue
Block a user