1 /* external.cc: Interface to Cygwin internals from external programs.
3 Written by Christopher Faylor <cgf@cygnus.com>
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
14 #include "shared_info.h"
15 #include "cygwin_version.h"
23 #include "child_info.h"
25 #include "cygserver_setpwd.h"
27 #include "exception.h"
33 child_info
*get_cygwin_startup_info ();
34 static void exit_process (UINT
, bool) __attribute__((noreturn
));
38 static external_pinfo
*
39 fillout_pinfo (pid_t pid
, int winpid
)
42 static external_pinfo ep
;
43 static char ep_progname_long_buf
[NT_MAX_PATH
];
45 if ((nextpid
= !!(pid
& CW_NEXTPID
)))
49 static unsigned int i
;
50 if (!pids
.npids
|| !nextpid
)
59 memset (&ep
, 0, sizeof ep
);
60 while (i
< pids
.npids
)
62 DWORD thispid
= pids
.winpid (i
);
66 /* Native Windows process not started from Cygwin have no procinfo
67 attached. They don't have a real Cygwin PID either. We fake a
68 Cygwin PID beyond MAX_PID. */
71 if (!nextpid
&& thispid
+ MAX_PID
!= (DWORD
) pid
)
73 ep
.pid
= thispid
+ MAX_PID
;
74 ep
.dwProcessId
= thispid
;
75 ep
.process_state
= PID_IN_USE
;
76 ep
.ctty
= CTTY_UNINITIALIZED
;
79 else if (nextpid
|| p
->pid
== pid
)
81 ep
.ctty
= (!CTTY_IS_VALID (p
->ctty
) || iscons_dev (p
->ctty
))
82 ? p
->ctty
: device::minor (p
->ctty
);
85 ep
.dwProcessId
= p
->dwProcessId
;
91 ep
.start_time
= p
->start_time
;
92 ep
.rusage_self
= p
->rusage_self
;
93 ep
.rusage_children
= p
->rusage_children
;
94 ep
.progname
[0] = '\0';
95 sys_wcstombs(ep
.progname
, MAX_PATH
, p
->progname
);
97 ep
.version
= EXTERNAL_PINFO_VERSION
;
99 ep
.process_state
= p
->process_state
;
104 ep
.progname_long
= ep_progname_long_buf
;
105 mount_table
->conv_to_posix_path (p
->progname
, ep
.progname_long
, 0);
119 static inline uintptr_t
120 get_cygdrive_info (char *user
, char *system
, char *user_flags
,
123 int res
= mount_table
->get_cygdrive_info (user
, system
, user_flags
,
125 return (res
== ERROR_SUCCESS
) ? 1 : 0;
129 check_ntsec (const char *filename
)
133 path_conv
pc (filename
);
134 return pc
.has_acls ();
137 /* Copy cygwin environment variables to the Windows environment. */
139 create_winenv (const char * const *env
)
142 PWCHAR envblock
= NULL
;
143 char **envp
= build_env (env
?: environ
, envblock
, unused_envc
, false,
149 for (char **e
= envp
; *e
; e
++)
153 /* If we got an env block, just return pointer to win env. */
156 /* Otherwise sync win env of current process with its posix env. */
161 PWCHAR eq
= wcschr (p
, L
'=');
165 SetEnvironmentVariableW (p
, ++eq
);
168 p
= wcschr (p
, L
'\0') + 1;
175 * Cygwin-specific wrapper for win32 ExitProcess and TerminateProcess.
176 * It ensures that the correct exit code, derived from the specified
177 * status value, will be made available to this process's parent (if
178 * that parent is also a cygwin process). If useTerminateProcess is
179 * true, then TerminateProcess(GetCurrentProcess(),...) will be used;
180 * otherwise, ExitProcess(...) is called.
182 * Used by startup code for cygwin processes which is linked statically
183 * into applications, and is not part of the cygwin DLL -- which is why
184 * this interface is exposed. "Normal" programs should use ANSI exit(),
185 * ANSI abort(), or POSIX _exit(), rather than this function -- because
186 * calling ExitProcess or TerminateProcess, even through this wrapper,
187 * skips much of the cygwin process cleanup code.
190 exit_process (UINT status
, bool useTerminateProcess
)
192 pid_t pid
= getpid ();
193 external_pinfo
*ep
= fillout_pinfo (pid
, 1);
194 DWORD dwpid
= ep
? ep
->dwProcessId
: pid
;
195 pinfo
p (pid
, PID_MAP_RW
);
198 if ((dwpid
== GetCurrentProcessId()) && (p
->pid
== pid
))
199 p
.set_exit_code ((DWORD
)status
);
200 if (useTerminateProcess
)
201 TerminateProcess (GetCurrentProcess(), status
);
202 /* avoid 'else' clause to silence warning */
203 ExitProcess (status
);
208 cygwin_internal (cygwin_getinfo_types t
, ...)
211 uintptr_t res
= (uintptr_t) -1;
220 case CW_UNLOCK_PINFO
:
224 case CW_GETTHREADNAME
:
225 res
= (uintptr_t) cygthread::name (va_arg (arg
, DWORD
));
228 case CW_SETTHREADNAME
:
236 res
= (uintptr_t) fillout_pinfo (va_arg (arg
, DWORD
), 0);
239 case CW_GETVERSIONINFO
:
240 res
= (uintptr_t) cygwin_version_strings
;
243 case CW_READ_V1_MOUNT_TABLES
:
249 res
= (uintptr_t) &__cygwin_user_data
;
253 perfile_table
= va_arg (arg
, struct __cygwin_perfile
*);
257 case CW_GET_CYGDRIVE_PREFIXES
:
259 char *user
= va_arg (arg
, char *);
260 char *system
= va_arg (arg
, char *);
261 res
= get_cygdrive_info (user
, system
, NULL
, NULL
);
265 case CW_GETPINFO_FULL
:
266 res
= (uintptr_t) fillout_pinfo (va_arg (arg
, pid_t
), 1);
269 case CW_INIT_EXCEPTIONS
:
270 /* noop */ /* init_exceptions (va_arg (arg, exception_list *)); */
274 case CW_GET_CYGDRIVE_INFO
:
276 char *user
= va_arg (arg
, char *);
277 char *system
= va_arg (arg
, char *);
278 char *user_flags
= va_arg (arg
, char *);
279 char *system_flags
= va_arg (arg
, char *);
280 res
= get_cygdrive_info (user
, system
, user_flags
, system_flags
);
284 case CW_SET_CYGWIN_REGISTRY_NAME
:
285 case CW_GET_CYGWIN_REGISTRY_NAME
:
289 case CW_STRACE_TOGGLE
:
291 pid_t pid
= va_arg (arg
, pid_t
);
295 sig_send (p
, __SIGSTRACE
);
301 res
= (uintptr_t) -1;
306 case CW_STRACE_ACTIVE
:
308 res
= strace
.active ();
312 case CW_CYGWIN_PID_TO_WINPID
:
314 pinfo
p (va_arg (arg
, pid_t
));
315 res
= p
? p
->dwProcessId
: 0;
319 case CW_WINPID_TO_CYGWIN_PID
:
321 DWORD winpid
= va_arg (arg
, DWORD
);
322 pid_t pid
= cygwin_pid (winpid
);
323 res
= pid
?: winpid
+ MAX_PID
;
327 case CW_MAX_CYGWIN_PID
:
331 case CW_EXTRACT_DOMAIN_AND_USER
:
333 WCHAR nt_domain
[MAX_DOMAIN_NAME_LEN
+ 1];
334 WCHAR nt_user
[UNLEN
+ 1];
336 struct passwd
*pw
= va_arg (arg
, struct passwd
*);
337 char *domain
= va_arg (arg
, char *);
338 char *user
= va_arg (arg
, char *);
339 extract_nt_dom_user (pw
, nt_domain
, nt_user
);
341 sys_wcstombs (domain
, MAX_DOMAIN_NAME_LEN
+ 1, nt_domain
);
343 sys_wcstombs (user
, UNLEN
+ 1, nt_user
);
348 case CW_CMDLINE_ALLOC
:
352 char *cmdline
= NULL
;
354 pid_t pid
= va_arg (arg
, pid_t
);
356 cmdline_cheap
= (p
? p
->cmdline (n
) : NULL
);
359 cmdline
= (char *) malloc (n
+ 1);
362 memcpy (cmdline
, cmdline_cheap
, n
);
365 cfree (cmdline_cheap
);
367 res
= (uintptr_t) cmdline
;
373 char *filename
= va_arg (arg
, char *);
374 res
= check_ntsec (filename
);
378 case CW_GET_ERRNO_FROM_WINERROR
:
380 int error
= va_arg (arg
, int);
381 int deferrno
= va_arg (arg
, int);
382 res
= geterrno_from_win_error (error
, deferrno
);
386 case CW_GET_POSIX_SECURITY_ATTRIBUTE
:
389 security_descriptor sd
;
390 int attribute
= va_arg (arg
, int);
391 PSECURITY_ATTRIBUTES psa
= va_arg (arg
, PSECURITY_ATTRIBUTES
);
392 void *sd_buf
= va_arg (arg
, void *);
393 DWORD sd_buf_size
= va_arg (arg
, DWORD
);
394 set_security_attribute (dummy
, attribute
, psa
, sd
);
395 if (!psa
->lpSecurityDescriptor
)
399 psa
->lpSecurityDescriptor
= sd_buf
;
400 res
= sd
.copy (sd_buf
, sd_buf_size
);
407 res
= wincap
.allocation_granularity ();
411 case CW_GET_UID_FROM_SID
:
413 cygpsid psid
= va_arg (arg
, PSID
);
414 res
= psid
.get_uid (NULL
);
418 case CW_GET_GID_FROM_SID
:
420 cygpsid psid
= va_arg (arg
, PSID
);
421 res
= psid
.get_gid (NULL
);
427 const char *path
= va_arg (arg
, const char *);
428 path_conv
p (path
, PC_SYM_FOLLOW
| PC_NULLEMPTY
);
432 res
= (unsigned long) -1;
441 const char *name
= va_arg (arg
, const char *);
442 const void *hookfn
= va_arg (arg
, const void *);
444 res
= (uintptr_t) hook_or_detect_cygwin (name
, hookfn
, subsys
);
450 child_info_spawn
*ci
= (child_info_spawn
*) get_cygwin_startup_info ();
451 res
= (uintptr_t) (ci
? ci
->moreinfo
->argv
: NULL
);
457 child_info_spawn
*ci
= (child_info_spawn
*) get_cygwin_startup_info ();
458 res
= (uintptr_t) (ci
? ci
->moreinfo
->envp
: NULL
);
463 error_start_init (va_arg (arg
, const char *));
464 res
= try_to_debug ();
468 create_winenv (NULL
);
472 case CW_CYGTLS_PADSIZE
:
473 res
= __CYGTLS_PADSIZE__
;
476 case CW_SET_DOS_FILE_WARNING
:
480 case CW_SET_PRIV_KEY
:
482 const char *passwd
= va_arg (arg
, const char *);
483 const char *username
= va_arg (arg
, const char *);
484 res
= setlsapwd (passwd
, username
);
490 const char *file
= va_arg (arg
, const char *);
491 int line
= va_arg (arg
, int);
492 seterrno(file
, line
);
497 case CW_EXIT_PROCESS
:
499 UINT status
= va_arg (arg
, UINT
);
500 int useTerminateProcess
= va_arg (arg
, int);
501 exit_process (status
, !!useTerminateProcess
); /* no return */
503 case CW_SET_EXTERNAL_TOKEN
:
505 HANDLE token
= va_arg (arg
, HANDLE
);
506 int type
= va_arg (arg
, int);
507 set_imp_token (token
, type
);
514 PWCHAR dest
= va_arg (arg
, PWCHAR
);
515 wcscpy (dest
, cygheap
->installation_key_buf
);
520 case CW_INT_SETLOCALE
:
522 extern void internal_setlocale ();
523 internal_setlocale ();
528 case CW_CVT_MNT_OPTS
:
530 extern bool fstab_read_flags (char **, unsigned &, bool);
531 char **option_string
= va_arg (arg
, char **);
532 if (!option_string
|| !*option_string
)
536 unsigned *pflags
= va_arg (arg
, unsigned *);
537 unsigned flags
= pflags
? *pflags
: 0;
538 if (fstab_read_flags (option_string
, flags
, true))
548 case CW_LST_MNT_OPTS
:
550 extern char *fstab_list_flags ();
551 char **option_string
= va_arg (arg
, char **);
556 *option_string
= fstab_list_flags ();
565 int err
= va_arg (arg
, int);
566 res
= (uintptr_t) strerror (err
);
570 case CW_CVT_ENV_TO_WINENV
:
572 char **posix_env
= va_arg (arg
, char **);
573 res
= (uintptr_t) create_winenv (posix_env
);
577 case CW_ALLOC_DRIVE_MAP
:
579 dos_drive_mappings
*ddm
= new dos_drive_mappings ();
580 res
= (uintptr_t) ddm
;
584 case CW_MAP_DRIVE_MAP
:
586 dos_drive_mappings
*ddm
= va_arg (arg
, dos_drive_mappings
*);
587 wchar_t *pathbuf
= va_arg (arg
, wchar_t *);
589 res
= (uintptr_t) ddm
->fixup_if_match (pathbuf
);
593 case CW_FREE_DRIVE_MAP
:
595 dos_drive_mappings
*ddm
= va_arg (arg
, dos_drive_mappings
*);
604 int group
= va_arg (arg
, int);
605 int enums
= va_arg (arg
, int);
606 PCWSTR enum_tdoms
= va_arg (arg
, PCWSTR
);
608 res
= (uintptr_t) setgrent_filtered (enums
, enum_tdoms
);
610 res
= (uintptr_t) setpwent_filtered (enums
, enum_tdoms
);
616 int group
= va_arg (arg
, int);
617 void *obj
= va_arg (arg
, void *);
621 res
= (uintptr_t) getgrent_filtered (obj
);
623 res
= (uintptr_t) getpwent_filtered (obj
);
630 int group
= va_arg (arg
, int);
631 void *obj
= va_arg (arg
, void *);
635 endgrent_filtered (obj
);
637 endpwent_filtered (obj
);
644 res
= (uintptr_t) NSS_SEPARATOR_STRING
;
647 case CW_GETNSS_PWD_SRC
:
648 res
= (uintptr_t) cygheap
->pg
.nss_pwd_src ();
651 case CW_GETNSS_GRP_SRC
:
652 res
= (uintptr_t) cygheap
->pg
.nss_grp_src ();
657 int db_only
= va_arg (arg
, int);
658 PSID psid
= va_arg (arg
, PSID
);
660 res
= (uintptr_t) (db_only
? internal_getpwsid_from_db (sid
)
661 : internal_getpwsid (sid
));
667 int db_only
= va_arg (arg
, int);
668 PSID psid
= va_arg (arg
, PSID
);
670 res
= (uintptr_t) (db_only
? internal_getgrsid_from_db (sid
)
671 : internal_getgrsid (sid
));
675 case CW_CYGNAME_FROM_WINNAME
:
677 /* This functionality has been added mainly for sshd. Sshd
678 calls getpwnam() with the username of the non-privileged
679 user used for privilege separation. This is usually a
680 fixed string "sshd". However, when using usernames from
681 the Windows DBs, it's no safe bet anymore if the username
682 is "sshd", it could also be "DOMAIN+sshd". So what we do
685 Sshd calls cygwin_internal (CW_CYGNAME_FROM_WINNAME,
688 sizeof username_buffer);
690 If this call succeeds, sshd expects the correct Cygwin
691 username of the unprivileged sshd account in username_buffer.
693 The below code checks for a Windows username matching the
694 incoming username, and then fetches the Cygwin username with
695 the matching SID. This is our username used for privsep then.
697 Of course, other applications with similar needs can use the
699 const char *winname
= va_arg (arg
, const char *);
700 char *buffer
= va_arg (arg
, char *);
701 size_t buflen
= va_arg (arg
, size_t);
703 if (!winname
|| !buffer
|| !buflen
)
706 WCHAR name
[UNLEN
+ 1];
707 sys_mbstowcs (name
, sizeof name
, winname
);
710 DWORD slen
= SECURITY_MAX_SID_SIZE
;
711 WCHAR dom
[DNLEN
+ 1];
712 DWORD dlen
= DNLEN
+ 1;
713 SID_NAME_USE acc_type
;
715 if (!LookupAccountNameW (NULL
, name
, sid
, &slen
, dom
, &dlen
,
719 struct passwd
*pw
= internal_getpwsid (sid
);
724 strncat (buffer
, pw
->pw_name
, buflen
- 1);
729 case CW_FIXED_ATEXIT
:
733 case CW_EXCEPTION_RECORD_FROM_SIGINFO_T
:
735 siginfo_t
*si
= va_arg(arg
, siginfo_t
*);
736 EXCEPTION_RECORD
*er
= va_arg(arg
, EXCEPTION_RECORD
*);
737 if (si
&& si
->si_cyg
&& er
)
739 memcpy(er
, ((cygwin_exception
*)si
->si_cyg
)->exception_record(),
740 sizeof(EXCEPTION_RECORD
));
746 case CW_CYGHEAP_PROFTHR_ALL
:
748 typedef void (*func_t
) (HANDLE
);
749 extern void cygheap_profthr_all (func_t
);
751 func_t profthr_byhandle
= va_arg(arg
, func_t
);
752 cygheap_profthr_all (profthr_byhandle
);