newlib/winsup/cygwin/fhandler_procsysvipc.cc

393 lines
9.6 KiB
C++
Raw Normal View History

/* fhandler_procsysvipc.cc: fhandler for /proc/sysvipc virtual filesystem
Introduce reading passwd/group entries from SAM/AD. Introduce /etc/nsswitch.conf file to configure it. * Makefile.in (DLL_OFILES): Add ldap.o. * autoload.cc: Import ldap functions from wldap32.dll. (DsEnumerateDomainTrustsW): Import. (NetGroupGetInfo): Import. * cygheap.h (class cygheap_domain_info): New class to keep global domain info. (class cygheap_pwdgrp): New class to keep passwd/group caches and configuration info from /etc/nssswitch.conf. (struct init_cygheap): Add cygheap_domain_info member "dom" and cygheap_pwdgrp member "pg". * cygtls.h (struct _local_storage): Remove unused member "res". Rearrange slightly, Add members pwbuf and grbuf to implement non-caching passwd/group fetching from SAM/AD. Make pw_pos and pw_pos unsigned. * fhandler_disk_file.cc (fhandler_base::fstat_by_nfs_ea): Add RFC 2307 uid/gid mapping. * fhandler_process.cc: Drop including pwdgrp.h. * fhandler_procsysvipc.cc: Ditto. * fhandler_registry.cc (fhandler_registry::fstat): Set key uid/gid to ILLEGAL_UID/ILLEGAL_GID rather than UNKNOWN_UID/UNKNOWN_GID. * grp.cc (group_buf): Drop. (gr): Drop. (pwdgrp::parse_group): Fill pg_grp. (pwdgrp::read_group): Remove. (pwdgrp::init_grp): New method. (pwdgrp::prep_tls_grbuf): New method. (pwdgrp::find_group): New methods. (internal_getgrsid): Convert to call new pwdgrp methods. (internal_getgrnam): Ditto. (internal_getgrgid): Ditto. (getgrgid_r): Drop 2nd parameter from internal_getgrgid call. (getgrgid32): Ditto. (getgrnam_r): Ditto for internal_getgrnam. (getgrnam32): Ditto. (getgrent32): Convert to call new pwdgrp methods. (internal_getgrent): Remove. (internal_getgroups): Simplify, especially drop calls to internal_getgrent. * ldap.cc: New file implementing cyg_ldap class for LDAP access to AD and RFC 2307 server. * ldap.h: New header, declaring cyg_ldap class. * passwd.cc (passwd_buf): Drop. (pr): Drop. (pwdgrp::parse_passwd): Fill pg_pwd. (pwdgrp::read_passwd): Remove. (pwdgrp::init_pwd): New method. (pwdgrp::prep_tls_pwbuf): New method. (find_user): New methods. (internal_getpwsid): Convert to call new pwdgrp methods. (internal_getpwnam): Ditto. (internal_getpwuid): Ditto. (getpwuid32): Drop 2nd parameter from internal_getpwuid call. (getpwuid_r): Ditto. (getpwnam): Ditto for internal_getpwnam. (getpwnam_r): Ditto. (getpwent): Convert to call new pwdgrp methods. * path.cc (class etc): Remove all methods. * path.h (class etc): Drop. * pinfo.cc (pinfo_basic::pinfo_basic): Set gid to ILLEGAL_GID rather than UNKNOWN_GID. (pinfo_init): Ditto. * pwdgrp.h (internal_getpwnam): Drop 2nd parameter from declaration. (internal_getpwuid): Ditto. (internal_getgrgid): Ditto. (internal_getgrnam): Ditto. (internal_getgrent): Drop declaration. (enum fetch_user_arg_type_t): New type. (struct fetch_user_arg_t): New type. (struct pg_pwd): New type. (struct pg_grp): New type. (class pwdgrp): Rework to provide functions for file and db requests and caching. (class ugid_cache_t): New class to provide RFC 2307 uid map caching. (ugid_cache): Declare. * sec_acl.cc: Drop including pwdgrp.h. * sec_auth.cc: Drop including dsgetdc.h and pwdgrp.h. (get_logon_server): Convert third parameter to ULONG flags argument to allow arbitrary flags values in DsGetDcNameW call and change calls to this function throughout. Use cached account domain name rather than calling GetComputerNameW. (get_unix_group_sidlist): Remove. (get_server_groups): Drop call to get_unix_group_sidlist. (verify_token): Rework token group check without calling internal_getgrent. * sec_helper.cc (cygpsid::pstring): New methods, like string() but return pointer to end of string. (cygsid::getfromstr): Add wide character implementation. (get_sids_info): Add RFC 2307 uid/gid mapping for Samba shares. * security.cc: Drop including pwdgrp.h. * security.h (DEFAULT_UID): Remove. (UNKNOWN_UID): Remove. (UNKNOWN_GID): Remove. (uinfo_init): Move here from winsup.h. (ILLEGAL_UID): Ditto. (ILLEGAL_GID): Ditto. (UNIX_POSIX_OFFSET): Define. Add lengthy comment. (UNIX_POSIX_MASK): Ditto. (MAP_UNIX_TO_CYGWIN_ID): Ditto. (ILLEGAL_UID16): Move here from winsup.h. (ILLEGAL_GID16): Ditto. (uid16touid32): Ditto. (gid16togid32): Ditto. (sid_id_auth): New convenience macro for SID component access. (sid_sub_auth_count): Ditto. (sid_sub_auth): Ditto. (sid_sub_auth_rid): Ditto. (cygpsid::pstring): Declare. (cygsid::getfromstr): Declare wide character variant. (cygsid::operator=): Ditto. (cygsid::operator*=): Ditto. (get_logon_server): Change declaration according to source code. * setlsapwd.cc (setlsapwd): Drop 2nd parameter from internal_getpwnam call. * shared.cc (memory_init): Call cygheap->pg.init in first process. * syscalls.cc: Drop including pwdgrp.h. * tlsoffsets.h: Regenerate. * tlsoffsets64.h: Ditto. * uinfo.cc (internal_getlogin): Drop gratuitious internal_getpwuid call. Fix debug output. Overwrite user gid in border case of a missing passwd file while a group file exists. (pwdgrp::add_line): Allocate memory on cygheap. (pwdgrp::load): Remove. (ugid_cache): Define. (cygheap_pwdgrp::init): New method. (cygheap_pwdgrp::nss_init_line): New method. (cygheap_pwdgrp::_nss_init): New method. (cygheap_domain_info::init): New method. (logon_sid): Define. (get_logon_sid): New function. (pwdgrp::add_account_post_fetch): New method. (pwdgrp::add_account_from_file): New methods. (pwdgrp::add_account_from_windows): New methods. (pwdgrp::check_file): New method. (pwdgrp::fetch_account_from_line): New method. (pwdgrp::fetch_account_from_file): New method. (pwdgrp::fetch_account_from_windows): New method. * winsup.h: Move aforementioned macros and declarations to security.h.
2014-02-09 20:44:56 +01:00
Copyright 2011, 2012, 2013, 2014 Red Hat, Inc.
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
#include <stdlib.h>
#include <stdio.h>
#include <sys/cygwin.h>
#include "cygerrno.h"
#include "cygserver.h"
#include "security.h"
#include "path.h"
#include "fhandler.h"
#include "fhandler_virtual.h"
#include "pinfo.h"
#include "shared_info.h"
#include "dtable.h"
#include "cygheap.h"
#include "ntdll.h"
#include "cygtls.h"
#include "tls_pbuf.h"
#include <sys/param.h>
#include <ctype.h>
#define _COMPILING_NEWLIB
#include <dirent.h>
#define _KERNEL
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <sys/shm.h>
2013-04-23 11:44:36 +02:00
static off_t format_procsysvipc_msg (void *, char *&);
static off_t format_procsysvipc_sem (void *, char *&);
static off_t format_procsysvipc_shm (void *, char *&);
static const virt_tab_t procsysvipc_tab[] =
{
2011-06-06 07:02:13 +02:00
{ _VN ("."), FH_PROCSYSVIPC, virt_directory, NULL },
{ _VN (".."), FH_PROCSYSVIPC, virt_directory, NULL },
{ _VN ("msg"), FH_PROCSYSVIPC, virt_file, format_procsysvipc_msg },
{ _VN ("sem"), FH_PROCSYSVIPC, virt_file, format_procsysvipc_sem },
{ _VN ("shm"), FH_PROCSYSVIPC, virt_file, format_procsysvipc_shm },
{ NULL, 0, FH_NADA, virt_none, NULL }
};
static const int PROCSYSVIPC_LINK_COUNT =
(sizeof (procsysvipc_tab) / sizeof (virt_tab_t)) - 1;
/* Returns 0 if path doesn't exist, >0 if path is a directory,
* -1 if path is a file.
*/
virtual_ftype_t
fhandler_procsysvipc::exists ()
{
const char *path = get_name ();
debug_printf ("exists (%s)", path);
path += proc_len + 1;
while (*path != 0 && !isdirsep (*path))
path++;
if (*path == 0)
return virt_rootdir;
virt_tab_t *entry = virt_tab_search (path + 1, true, procsysvipc_tab,
PROCSYSVIPC_LINK_COUNT);
cygserver_init ();
if (entry)
{
if (entry->type == virt_file)
2011-06-06 07:02:13 +02:00
{
if (cygserver_running != CYGSERVER_OK)
return virt_none;
}
fileid = entry - procsysvipc_tab;
return entry->type;
}
return virt_none;
}
fhandler_procsysvipc::fhandler_procsysvipc ():
fhandler_proc ()
{
}
int __reg2
2013-04-23 11:44:36 +02:00
fhandler_procsysvipc::fstat (struct stat *buf)
{
fhandler_base::fstat (buf);
buf->st_mode &= ~_IFMT & NO_W;
int file_type = exists ();
switch (file_type)
{
case virt_none:
set_errno (ENOENT);
return -1;
case virt_directory:
case virt_rootdir:
buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
buf->st_nlink = 2;
return 0;
case virt_file:
default:
buf->st_mode |= S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
return 0;
}
}
int
fhandler_procsysvipc::readdir (DIR *dir, dirent *de)
{
int res = ENMFILE;
if (dir->__d_position >= PROCSYSVIPC_LINK_COUNT)
goto out;
{
cygserver_init ();
if (cygserver_running != CYGSERVER_OK)
goto out;
}
strcpy (de->d_name, procsysvipc_tab[dir->__d_position++].name);
dir->__flags |= dirent_saw_dot | dirent_saw_dot_dot;
res = 0;
out:
syscall_printf ("%d = readdir(%p, %p) (%s)", res, dir, de, de->d_name);
return res;
}
int
fhandler_procsysvipc::open (int flags, mode_t mode)
{
int res = fhandler_virtual::open (flags, mode);
if (!res)
goto out;
nohandle (true);
const char *path;
path = get_name () + proc_len + 1;
pid = atoi (path);
while (*path != 0 && !isdirsep (*path))
path++;
if (*path == 0)
{
if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
{
set_errno (EEXIST);
res = 0;
goto out;
}
else if (flags & O_WRONLY)
{
set_errno (EISDIR);
res = 0;
goto out;
}
else
{
flags |= O_DIROPEN;
goto success;
}
}
virt_tab_t *entry;
entry = virt_tab_search (path + 1, true, procsysvipc_tab, PROCSYSVIPC_LINK_COUNT);
if (!entry)
{
set_errno ((flags & O_CREAT) ? EROFS : ENOENT);
res = 0;
goto out;
}
if (flags & O_WRONLY)
{
set_errno (EROFS);
res = 0;
goto out;
}
fileid = entry - procsysvipc_tab;
if (!fill_filebuf ())
{
res = 0;
goto out;
}
if (flags & O_APPEND)
position = filesize;
else
position = 0;
success:
res = 1;
set_flags ((flags & ~O_TEXT) | O_BINARY);
set_open_status ();
out:
2013-04-23 11:44:36 +02:00
syscall_printf ("%d = fhandler_proc::open(%p, 0%o)", res, flags, mode);
return res;
}
bool
fhandler_procsysvipc::fill_filebuf ()
{
if (procsysvipc_tab[fileid].format_func)
{
filesize = procsysvipc_tab[fileid].format_func (NULL, filebuf);
return true;
}
return false;
}
#define MSG_HEADLINE " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n"
2013-04-23 11:44:36 +02:00
static off_t
format_procsysvipc_msg (void *, char *&destbuf)
{
char *buf;
struct msginfo msginfo;
struct msqid_ds *xmsqids;
msgctl (0, IPC_INFO, (struct msqid_ds *) &msginfo);
/* Don't use tmp_pathbuf. The required buffer sizes can be up to 128K! */
xmsqids = (struct msqid_ds *) malloc (sizeof (struct msqid_ds)
* msginfo.msgmni);
if (!xmsqids)
return 0;
/* buf size = sizeof headline + 128 bytes per msg queue entry. */
buf = (char *) malloc (sizeof (MSG_HEADLINE) + msginfo.msgmni * 128);
if (!buf)
{
free (xmsqids);
return 0;
}
char *bufptr = stpcpy (buf, MSG_HEADLINE);
msgctl (msginfo.msgmni, IPC_INFO, (struct msqid_ds *) xmsqids);
for (int i = 0; i < msginfo.msgmni; i++)
{
if (xmsqids[i].msg_qbytes != 0)
{
bufptr += sprintf (bufptr,
"%10llu %10u %5o %11u %10u %5d %5d %5u %5u %5u %5u "
"%10ld %10ld %10ld\n",
xmsqids[i].msg_perm.key,
IXSEQ_TO_IPCID(i, xmsqids[i].msg_perm),
xmsqids[i].msg_perm.mode,
xmsqids[i].msg_cbytes,
xmsqids[i].msg_qnum,
xmsqids[i].msg_lspid,
xmsqids[i].msg_lrpid,
(unsigned) xmsqids[i].msg_perm.uid,
(unsigned) xmsqids[i].msg_perm.gid,
(unsigned) xmsqids[i].msg_perm.cuid,
(unsigned) xmsqids[i].msg_perm.cgid,
xmsqids[i].msg_stime,
xmsqids[i].msg_rtime,
xmsqids[i].msg_ctime);
}
}
off_t size = bufptr - buf;
destbuf = (char *) crealloc_abort (destbuf, size);
memcpy (destbuf, buf, size);
free (buf);
free (xmsqids);
return size;
}
#undef MSG_HEADLINE
#define SEM_HEADLINE " key semid perms nsems uid gid cuid cgid otime ctime\n"
2013-04-23 11:44:36 +02:00
static off_t
format_procsysvipc_sem (void *, char *&destbuf)
{
char *buf;
union semun semun;
struct seminfo seminfo;
struct semid_ds *xsemids;
semun.buf = (struct semid_ds *) &seminfo;
semctl (0, 0, IPC_INFO, semun);
/* Don't use tmp_pathbuf. The required buffer sizes can be up to 96K! */
xsemids = (struct semid_ds *) malloc (sizeof (struct semid_ds)
* seminfo.semmni);
if (!xsemids)
return 0;
/* buf size = sizeof headline + 96 bytes per semaphore entry. */
buf = (char *) malloc (sizeof (SEM_HEADLINE) + seminfo.semmni * 96);
if (!buf)
{
free (xsemids);
return 0;
}
char *bufptr = stpcpy (buf, SEM_HEADLINE);
semun.buf = xsemids;
semctl (seminfo.semmni, 0, IPC_INFO, semun);
for (int i = 0; i < seminfo.semmni; i++)
{
if ((xsemids[i].sem_perm.mode & SEM_ALLOC) != 0)
{
bufptr += sprintf (bufptr,
"%10llu %10u %5o %10d %5u %5u %5u %5u %10ld %10ld\n",
xsemids[i].sem_perm.key,
IXSEQ_TO_IPCID(i, xsemids[i].sem_perm),
xsemids[i].sem_perm.mode,
xsemids[i].sem_nsems,
(unsigned) xsemids[i].sem_perm.uid,
(unsigned) xsemids[i].sem_perm.gid,
(unsigned) xsemids[i].sem_perm.cuid,
(unsigned) xsemids[i].sem_perm.cgid,
xsemids[i].sem_otime,
xsemids[i].sem_ctime);
}
}
off_t size = bufptr - buf;
destbuf = (char *) crealloc_abort (destbuf, size);
memcpy (destbuf, buf, size);
free (buf);
free (xsemids);
return size;
}
#undef SEM_HEADLINE
#define SHM_HEADLINE " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n"
2013-04-23 11:44:36 +02:00
static off_t
format_procsysvipc_shm (void *, char *&destbuf)
{
char *buf;
struct shminfo shminfo;
struct shmid_ds *xshmids;
shmctl (0, IPC_INFO, (struct shmid_ds *) &shminfo);
/* Don't use tmp_pathbuf. The required buffer sizes can be up to 120K! */
xshmids = (struct shmid_ds *) malloc (sizeof (struct shmid_ds)
* shminfo.shmmni);
if (!xshmids)
return 0;
/* buf size = sizeof headline + 120 bytes per shmem entry. */
buf = (char *) malloc (sizeof (SHM_HEADLINE) + shminfo.shmmni * 120);
if (!buf)
{
free (xshmids);
return 0;
}
char *bufptr = stpcpy (buf, SHM_HEADLINE);
shmctl (shminfo.shmmni, IPC_INFO, (struct shmid_ds *) xshmids);
for (int i = 0; i < shminfo.shmmni; i++)
{
if (xshmids[i].shm_perm.mode & 0x0800)
{
bufptr += sprintf (bufptr,
"%10llu %10u %5o %10u %5d %5d %6u %5u %5u %5u %5u "
"%10ld %10ld %10ld\n",
xshmids[i].shm_perm.key,
IXSEQ_TO_IPCID(i, xshmids[i].shm_perm),
xshmids[i].shm_perm.mode,
xshmids[i].shm_segsz,
xshmids[i].shm_cpid,
xshmids[i].shm_lpid,
xshmids[i].shm_nattch,
(unsigned) xshmids[i].shm_perm.uid,
(unsigned) xshmids[i].shm_perm.gid,
(unsigned) xshmids[i].shm_perm.cuid,
(unsigned) xshmids[i].shm_perm.cgid,
xshmids[i].shm_atime,
xshmids[i].shm_dtime,
xshmids[i].shm_ctime);
}
}
off_t size = bufptr - buf;
destbuf = (char *) crealloc_abort (destbuf, size);
memcpy (destbuf, buf, size);
free (buf);
free (xshmids);
return size;
}
#undef SHM_HEADLINE