You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
638 lines
12 KiB
638 lines
12 KiB
/*
|
|
|
|
Copyright 1989, 1998 The Open Group
|
|
Copyright 2000-2005 Oswald Buddenhagen <ossi@kde.org>
|
|
|
|
Permission to use, copy, modify, distribute, and sell this software and its
|
|
documentation for any purpose is hereby granted without fee, provided that
|
|
the above copyright notice appear in all copies and that both that
|
|
copyright notice and this permission notice appear in supporting
|
|
documentation.
|
|
|
|
The above copyright notice and this permission notice shall be included
|
|
in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of a copyright holder shall
|
|
not be used in advertising or otherwise to promote the sale, use or
|
|
other dealings in this Software without prior written authorization
|
|
from the copyright holder.
|
|
|
|
*/
|
|
|
|
/*
|
|
* xdm - display manager daemon
|
|
* Author: Keith Packard, MIT X Consortium
|
|
*
|
|
* various utility routines
|
|
*/
|
|
|
|
#include "dm.h"
|
|
#include "dm_auth.h"
|
|
#include "dm_error.h"
|
|
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#if 0 /*def USG; this was hpux once upon a time */
|
|
# define NEED_UTSNAME
|
|
#endif
|
|
|
|
#ifdef NEED_UTSNAME
|
|
# include <sys/utsname.h>
|
|
#endif
|
|
|
|
void *
|
|
Calloc( size_t nmemb, size_t size )
|
|
{
|
|
void *ret;
|
|
|
|
if (!(ret = calloc( nmemb, size )))
|
|
LogOutOfMem();
|
|
return ret;
|
|
}
|
|
|
|
void *
|
|
Malloc( size_t size )
|
|
{
|
|
void *ret;
|
|
|
|
if (!(ret = malloc( size )))
|
|
LogOutOfMem();
|
|
return ret;
|
|
}
|
|
|
|
void *
|
|
Realloc( void *ptr, size_t size )
|
|
{
|
|
void *ret;
|
|
|
|
if (!(ret = realloc( ptr, size )) && size)
|
|
LogOutOfMem();
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
StrCmp( const char *s1, const char *s2 )
|
|
{
|
|
if (s1 == s2)
|
|
return 0;
|
|
if (!s1)
|
|
return -1;
|
|
if (!s2)
|
|
return 1;
|
|
return strcmp( s1, s2 );
|
|
}
|
|
|
|
void
|
|
WipeStr( char *str )
|
|
{
|
|
if (str) {
|
|
bzero( str, strlen( str ) );
|
|
free( str );
|
|
}
|
|
}
|
|
|
|
#ifndef HAVE_STRNLEN
|
|
int
|
|
StrNLen( const char *s, int max )
|
|
{
|
|
unsigned l;
|
|
|
|
for (l = 0; l < (unsigned)max && s[l]; l++);
|
|
return l;
|
|
}
|
|
#endif
|
|
|
|
/* duplicate src; wipe & free old dst string */
|
|
int
|
|
ReStrN( char **dst, const char *src, int len )
|
|
{
|
|
char *ndst = 0;
|
|
|
|
if (src) {
|
|
if (len < 0)
|
|
len = strlen( src );
|
|
if (*dst && !memcmp( *dst, src, len ) && !(*dst)[len])
|
|
return 1;
|
|
if (!(ndst = Malloc( len + 1 ))) {
|
|
WipeStr( *dst );
|
|
*dst = 0;
|
|
return 0;
|
|
}
|
|
memcpy( ndst, src, len );
|
|
ndst[len] = 0;
|
|
}
|
|
WipeStr( *dst ); /* make an option, if we should become heavily used */
|
|
*dst = ndst;
|
|
return 2;
|
|
}
|
|
|
|
int
|
|
ReStr( char **dst, const char *src )
|
|
{
|
|
return ReStrN( dst, src, -1 );
|
|
}
|
|
|
|
/* duplicate src */
|
|
int
|
|
StrNDup( char **dst, const char *src, int len )
|
|
{
|
|
if (src) {
|
|
if (len < 0)
|
|
len = strlen( src );
|
|
if (!(*dst = Malloc( len + 1 )))
|
|
return 0;
|
|
memcpy( *dst, src, len );
|
|
(*dst)[len] = 0;
|
|
} else
|
|
*dst = 0;
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
StrDup( char **dst, const char *src )
|
|
{
|
|
return StrNDup( dst, src, -1 );
|
|
}
|
|
|
|
/* append any number of strings to dst */
|
|
int
|
|
StrApp( char **dst, ... )
|
|
{
|
|
int len;
|
|
char *bk, *pt, *dp;
|
|
va_list va;
|
|
|
|
len = 1;
|
|
if (*dst)
|
|
len += strlen( *dst );
|
|
va_start( va, dst );
|
|
for (;;) {
|
|
pt = va_arg( va, char * );
|
|
if (!pt)
|
|
break;
|
|
len += strlen( pt );
|
|
}
|
|
va_end( va );
|
|
if (!(bk = Malloc( len ))) {
|
|
if (*dst) {
|
|
free( *dst );
|
|
*dst = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
dp = bk;
|
|
if (*dst) {
|
|
len = strlen( *dst );
|
|
memcpy( dp, *dst, len );
|
|
dp += len;
|
|
free( *dst );
|
|
}
|
|
va_start( va, dst );
|
|
for (;;) {
|
|
pt = va_arg( va, char * );
|
|
if (!pt)
|
|
break;
|
|
len = strlen( pt );
|
|
memcpy( dp, pt, len );
|
|
dp += len;
|
|
}
|
|
va_end( va );
|
|
*dp = '\0';
|
|
*dst = bk;
|
|
return 1;
|
|
}
|
|
|
|
|
|
char **
|
|
initStrArr( char **arr )
|
|
{
|
|
if (!arr && (arr = Malloc( sizeof(char *) )))
|
|
arr[0] = 0;
|
|
return arr;
|
|
}
|
|
|
|
int
|
|
arrLen( char **arr )
|
|
{
|
|
int nu = 0;
|
|
if (arr)
|
|
for (; arr[nu]; nu++);
|
|
return nu;
|
|
}
|
|
|
|
static char **
|
|
extStrArr( char **arr, char ***strp )
|
|
{
|
|
char **rarr;
|
|
int nu;
|
|
|
|
nu = arrLen( arr );
|
|
if ((rarr = Realloc( arr, sizeof(char *) * (nu + 2) ))) {
|
|
rarr[nu + 1] = 0;
|
|
*strp = rarr + nu;
|
|
return rarr;
|
|
}
|
|
freeStrArr( arr );
|
|
return 0;
|
|
}
|
|
|
|
char **
|
|
addStrArr( char **arr, const char *str, int len )
|
|
{
|
|
char **strp;
|
|
|
|
if ((arr = extStrArr( arr, &strp ))) {
|
|
if (StrNDup( strp, str, len ))
|
|
return arr;
|
|
freeStrArr( arr );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
char **
|
|
xCopyStrArr( int rn, char **arr )
|
|
{
|
|
char **rarr;
|
|
int nu;
|
|
|
|
nu = arrLen( arr );
|
|
if ((rarr = Calloc( sizeof(char *), nu + rn + 1 )))
|
|
memcpy( rarr + rn, arr, sizeof(char *) * nu );
|
|
return rarr;
|
|
}
|
|
|
|
void
|
|
freeStrArr( char **arr )
|
|
{
|
|
char **a;
|
|
|
|
if (arr) {
|
|
for (a = arr; *a; a++)
|
|
free( *a );
|
|
free( arr );
|
|
}
|
|
}
|
|
|
|
|
|
char **
|
|
parseArgs( char **argv, const char *string )
|
|
{
|
|
const char *word;
|
|
char **strp, *str;
|
|
int wlen;
|
|
|
|
if (!(argv = initStrArr( argv )))
|
|
return 0;
|
|
while (*string) {
|
|
if (isspace( *string )) {
|
|
string++;
|
|
continue;
|
|
}
|
|
word = string;
|
|
wlen = 0;
|
|
do {
|
|
if (*string == '\\') {
|
|
if (!*++string)
|
|
string--;
|
|
wlen++;
|
|
} else if (*string == '\'') {
|
|
while (*++string != '\'' && *string)
|
|
wlen++;
|
|
} else if (*string == '"') {
|
|
while (*++string != '"' && *string) {
|
|
if (*string == '\\') {
|
|
if (!*++string)
|
|
string--;
|
|
}
|
|
wlen++;
|
|
}
|
|
} else
|
|
wlen++;
|
|
} while (*++string && !isspace( *string ));
|
|
if (!(argv = extStrArr( argv, &strp )))
|
|
return 0;
|
|
if (!(*strp = str = Malloc( wlen + 1 ))) {
|
|
freeStrArr( argv );
|
|
return 0;
|
|
}
|
|
do {
|
|
if (*word == '\\') {
|
|
if (!*++word)
|
|
word--;
|
|
*str++ = *word;
|
|
} else if (*word == '\'') {
|
|
while (*++word != '\'' && *word)
|
|
*str++ = *word;
|
|
} else if (*word == '"') {
|
|
while (*++word != '"' && *word) {
|
|
if (*word == '\\') {
|
|
if (!*++word)
|
|
word--;
|
|
}
|
|
*str++ = *word;
|
|
}
|
|
} else
|
|
*str++ = *word;
|
|
} while (*++word && !isspace( *word ));
|
|
*str = 0;
|
|
}
|
|
return argv;
|
|
}
|
|
|
|
|
|
const char *
|
|
getEnv( char **e, const char *name )
|
|
{
|
|
if (e) {
|
|
int l = strlen( name );
|
|
for (; *e; e++)
|
|
if (!memcmp( *e, name, l ) && (*e)[l] == '=')
|
|
return (*e) + l + 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
char **
|
|
setEnv( char **e, const char *name, const char *value )
|
|
{
|
|
char **new, **old;
|
|
char *newe;
|
|
int envsize;
|
|
int l;
|
|
|
|
#ifdef _AIX
|
|
/* setpenv() depends on "SYSENVIRON:", not "SYSENVIRON:=" */
|
|
if (!value) {
|
|
if (!StrDup( &newe, name ))
|
|
return e;
|
|
} else
|
|
#endif
|
|
{
|
|
newe = 0;
|
|
if (!StrApp( &newe, name, "=", value, (char *)0 ))
|
|
return e;
|
|
}
|
|
envsize = 0;
|
|
if (e) {
|
|
l = strlen( name );
|
|
for (old = e; *old; old++)
|
|
if (!memcmp( *old, name, l ) && ((*old)[l] == '=' || !(*old)[l]))
|
|
{
|
|
free( *old );
|
|
*old = newe;
|
|
return e;
|
|
}
|
|
envsize = old - e;
|
|
}
|
|
if (!(new = (char **)
|
|
Realloc( (char *)e, (unsigned)((envsize + 2) * sizeof(char *)) )))
|
|
{
|
|
free( newe );
|
|
return e;
|
|
}
|
|
new[envsize] = newe;
|
|
new[envsize + 1] = 0;
|
|
return new;
|
|
}
|
|
|
|
char **
|
|
putEnv( const char *string, char **env )
|
|
{
|
|
char *n;
|
|
char *b;
|
|
|
|
if (!(b = (char*)strchr( string, '=' )))
|
|
return NULL;
|
|
if (!StrNDup( &n, string, b - string ))
|
|
return NULL;
|
|
env = setEnv( env, n, b + 1 );
|
|
free( n );
|
|
return env;
|
|
}
|
|
|
|
static int
|
|
GetHostname( char *buf, int maxlen )
|
|
{
|
|
int len;
|
|
|
|
#ifdef NEED_UTSNAME
|
|
/*
|
|
* same host name crock as in server and xinit.
|
|
*/
|
|
struct utsname name;
|
|
|
|
uname( &name );
|
|
len = strlen( name.nodename );
|
|
if (len >= maxlen) len = maxlen - 1;
|
|
memcpy( buf, name.nodename, len );
|
|
buf[len] = '\0';
|
|
#else
|
|
buf[0] = '\0';
|
|
(void)gethostname( buf, maxlen );
|
|
buf[maxlen - 1] = '\0';
|
|
len = strlen( buf );
|
|
#endif /* NEED_UTSNAME */
|
|
return len;
|
|
}
|
|
|
|
static char localHostbuf[256];
|
|
static int gotLocalHostname;
|
|
|
|
const char *
|
|
localHostname( void )
|
|
{
|
|
if (!gotLocalHostname)
|
|
{
|
|
GetHostname( localHostbuf, sizeof(localHostbuf) - 1 );
|
|
gotLocalHostname = 1;
|
|
}
|
|
return localHostbuf;
|
|
}
|
|
|
|
static int
|
|
AtomicIO( ssize_t (*f)( int, void *, size_t ), int fd, void *buf, int count )
|
|
{
|
|
int ret, rlen;
|
|
|
|
for (rlen = 0; rlen < count; ) {
|
|
dord:
|
|
ret = f( fd, (void *)((char *)buf + rlen), count - rlen );
|
|
if (ret < 0) {
|
|
if (errno == EINTR)
|
|
goto dord;
|
|
if (errno == EAGAIN)
|
|
break;
|
|
return -1;
|
|
}
|
|
if (!ret)
|
|
break;
|
|
rlen += ret;
|
|
}
|
|
return rlen;
|
|
}
|
|
|
|
int
|
|
Reader( int fd, void *buf, int count )
|
|
{
|
|
return AtomicIO( read, fd, buf, count );
|
|
}
|
|
|
|
int
|
|
Writer( int fd, const void *buf, int count )
|
|
{
|
|
return AtomicIO( (ssize_t(*)( int, void *, size_t ))write,
|
|
fd, (void *)buf, count );
|
|
}
|
|
|
|
int
|
|
fGets( char *buf, int max, FILE *f )
|
|
{
|
|
int len;
|
|
|
|
if (!fgets( buf, max, f ))
|
|
return -1;
|
|
len = strlen( buf );
|
|
if (len && buf[len - 1] == '\n')
|
|
buf[--len] = 0;
|
|
return len;
|
|
}
|
|
|
|
time_t
|
|
mTime( const char *fn )
|
|
{
|
|
struct stat st;
|
|
|
|
if (stat( fn, &st ))
|
|
return -1;
|
|
else
|
|
return st.st_mtime;
|
|
}
|
|
|
|
void
|
|
randomStr( char *s )
|
|
{
|
|
static const char letters[] =
|
|
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
unsigned i, rn = secureRandom();
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
*s++ = letters[rn % 62];
|
|
rn /= 62;
|
|
}
|
|
*s = 0;
|
|
}
|
|
|
|
static int
|
|
StrNChrCnt( const char *s, int slen, char c )
|
|
{
|
|
int i, cnt;
|
|
|
|
for (i = cnt = 0; i < slen && s[i]; i++)
|
|
if (s[i] == c)
|
|
cnt++;
|
|
return cnt;
|
|
}
|
|
|
|
/* X -from ip6-addr does not work here, so i don't know whether this is needed.
|
|
#define IP6_MAGIC
|
|
*/
|
|
|
|
void
|
|
ListSessions( int flags, struct display *d, void *ctx,
|
|
void (*emitXSess)( struct display *, struct display *, void * ),
|
|
void (*emitTTYSess)( STRUCTUTMP *, struct display *, void * ) )
|
|
{
|
|
struct display *di;
|
|
#ifdef IP6_MAGIC
|
|
int le, dot;
|
|
#endif
|
|
#ifdef BSD_UTMP
|
|
int fd;
|
|
struct utmp ut[1];
|
|
#else
|
|
STRUCTUTMP *ut;
|
|
#endif
|
|
|
|
for (di = displays; di; di = di->next)
|
|
if (((flags & lstRemote) || (di->displayType & d_location) == dLocal) &&
|
|
(di->status == remoteLogin ||
|
|
((flags & lstPassive) ? di->status == running : di->userSess >= 0)))
|
|
emitXSess( di, d, ctx );
|
|
|
|
if (!(flags & lstTTY))
|
|
return;
|
|
|
|
#ifdef BSD_UTMP
|
|
if ((fd = open( UTMP_FILE, O_RDONLY )) < 0)
|
|
return;
|
|
while (Reader( fd, ut, sizeof(ut[0]) ) == sizeof(ut[0])) {
|
|
if (*ut->ut_user) { /* no idea how to list passive TTYs on BSD */
|
|
#else
|
|
SETUTENT();
|
|
while ((ut = GETUTENT())) {
|
|
if (ut->ut_type == USER_PROCESS
|
|
# if 0 /* list passive TTYs at all? not too sensible, i think. */
|
|
|| ((flags & lstPassive) && ut->ut_type == LOGIN_PROCESS)
|
|
# endif
|
|
)
|
|
{
|
|
#endif
|
|
if (*ut->ut_host) { /* from remote or x */
|
|
if (!(flags & lstRemote))
|
|
continue;
|
|
} else {
|
|
/* hack around broken konsole which does not set ut_host. */
|
|
/* this check is probably linux-specific. */
|
|
/* alternatively we could open the device and try VT_OPENQRY. */
|
|
if (memcmp( ut->ut_line, "tty", 3 ) ||
|
|
!isdigit( ut->ut_line[3] ))
|
|
continue;
|
|
}
|
|
if (StrNChrCnt( ut->ut_line, sizeof(ut->ut_line), ':' ))
|
|
continue; /* x login */
|
|
switch (StrNChrCnt( ut->ut_host, sizeof(ut->ut_host), ':' )) {
|
|
case 1: /* x terminal */
|
|
continue;
|
|
default:
|
|
#ifdef IP6_MAGIC
|
|
/* unknown - IPv6 makes things complicated */
|
|
le = StrNLen( ut->ut_host, sizeof(ut->ut_host) );
|
|
/* cut off screen number */
|
|
for (dot = le; ut->ut_host[--dot] != ':'; )
|
|
if (ut->ut_host[dot] == '.') {
|
|
le = dot;
|
|
break;
|
|
}
|
|
for (di = displays; di; di = di->next)
|
|
if (!memcmp( di->name, ut->ut_host, le ) && !di->name[le])
|
|
goto cont; /* x terminal */
|
|
break;
|
|
cont:
|
|
continue;
|
|
case 0: /* no x terminal */
|
|
#endif
|
|
break;
|
|
}
|
|
emitTTYSess( ut, d, ctx );
|
|
}
|
|
}
|
|
#ifdef BSD_UTMP
|
|
close( fd );
|
|
#else
|
|
ENDUTENT();
|
|
#endif
|
|
}
|
|
|