xref: /freebsd/crypto/openssh/openbsd-compat/bsd-cygwin_util.c (revision 5e8dbd04ef7b2df5ba3f8dc859ad6e472ce1c534)
183d2307dSDag-Erling Smørgrav /*
283d2307dSDag-Erling Smørgrav  * Copyright (c) 2000, 2001, Corinna Vinschen <vinschen@cygnus.com>
383d2307dSDag-Erling Smørgrav  *
483d2307dSDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
583d2307dSDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
683d2307dSDag-Erling Smørgrav  * are met:
783d2307dSDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
883d2307dSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer.
983d2307dSDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
1083d2307dSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
1183d2307dSDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
1283d2307dSDag-Erling Smørgrav  *
1383d2307dSDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1483d2307dSDag-Erling Smørgrav  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1583d2307dSDag-Erling Smørgrav  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1683d2307dSDag-Erling Smørgrav  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1783d2307dSDag-Erling Smørgrav  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1883d2307dSDag-Erling Smørgrav  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1983d2307dSDag-Erling Smørgrav  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2083d2307dSDag-Erling Smørgrav  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2183d2307dSDag-Erling Smørgrav  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2283d2307dSDag-Erling Smørgrav  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2383d2307dSDag-Erling Smørgrav  *
2483d2307dSDag-Erling Smørgrav  * Created: Sat Sep 02 12:17:00 2000 cv
2583d2307dSDag-Erling Smørgrav  *
2683d2307dSDag-Erling Smørgrav  * This file contains functions for forcing opened file descriptors to
2783d2307dSDag-Erling Smørgrav  * binary mode on Windows systems.
2883d2307dSDag-Erling Smørgrav  */
2983d2307dSDag-Erling Smørgrav 
3083d2307dSDag-Erling Smørgrav #include "includes.h"
3183d2307dSDag-Erling Smørgrav 
325e8dbd04SDag-Erling Smørgrav RCSID("$Id: bsd-cygwin_util.c,v 1.13 2004/08/30 10:42:08 dtucker Exp $");
3383d2307dSDag-Erling Smørgrav 
3483d2307dSDag-Erling Smørgrav #ifdef HAVE_CYGWIN
3583d2307dSDag-Erling Smørgrav 
3683d2307dSDag-Erling Smørgrav #include <fcntl.h>
3783d2307dSDag-Erling Smørgrav #include <stdlib.h>
3883d2307dSDag-Erling Smørgrav #include <sys/utsname.h>
3983d2307dSDag-Erling Smørgrav #include <sys/vfs.h>
4083d2307dSDag-Erling Smørgrav #include <windows.h>
415e8dbd04SDag-Erling Smørgrav #include "xmalloc.h"
4283d2307dSDag-Erling Smørgrav #define is_winnt       (GetVersion() < 0x80000000)
4383d2307dSDag-Erling Smørgrav 
4483d2307dSDag-Erling Smørgrav #define ntsec_on(c)	((c) && strstr((c),"ntsec") && !strstr((c),"nontsec"))
45d0c8c0bcSDag-Erling Smørgrav #define ntsec_off(c)	((c) && strstr((c),"nontsec"))
4683d2307dSDag-Erling Smørgrav #define ntea_on(c)	((c) && strstr((c),"ntea") && !strstr((c),"nontea"))
4783d2307dSDag-Erling Smørgrav 
4883d2307dSDag-Erling Smørgrav #if defined(open) && open == binary_open
4983d2307dSDag-Erling Smørgrav # undef open
5083d2307dSDag-Erling Smørgrav #endif
5183d2307dSDag-Erling Smørgrav #if defined(pipe) && open == binary_pipe
5283d2307dSDag-Erling Smørgrav # undef pipe
5383d2307dSDag-Erling Smørgrav #endif
5483d2307dSDag-Erling Smørgrav 
55d95e11bfSDag-Erling Smørgrav int
56d95e11bfSDag-Erling Smørgrav binary_open(const char *filename, int flags, ...)
5783d2307dSDag-Erling Smørgrav {
5883d2307dSDag-Erling Smørgrav 	va_list ap;
5983d2307dSDag-Erling Smørgrav 	mode_t mode;
6083d2307dSDag-Erling Smørgrav 
6183d2307dSDag-Erling Smørgrav 	va_start(ap, flags);
6283d2307dSDag-Erling Smørgrav 	mode = va_arg(ap, mode_t);
6383d2307dSDag-Erling Smørgrav 	va_end(ap);
64d95e11bfSDag-Erling Smørgrav 	return (open(filename, flags | O_BINARY, mode));
6583d2307dSDag-Erling Smørgrav }
6683d2307dSDag-Erling Smørgrav 
67d95e11bfSDag-Erling Smørgrav int
68d95e11bfSDag-Erling Smørgrav binary_pipe(int fd[2])
6983d2307dSDag-Erling Smørgrav {
7083d2307dSDag-Erling Smørgrav 	int ret = pipe(fd);
7183d2307dSDag-Erling Smørgrav 
7283d2307dSDag-Erling Smørgrav 	if (!ret) {
7383d2307dSDag-Erling Smørgrav 		setmode(fd[0], O_BINARY);
7483d2307dSDag-Erling Smørgrav 		setmode(fd[1], O_BINARY);
7583d2307dSDag-Erling Smørgrav 	}
76d95e11bfSDag-Erling Smørgrav 	return (ret);
7783d2307dSDag-Erling Smørgrav }
7883d2307dSDag-Erling Smørgrav 
79d0c8c0bcSDag-Erling Smørgrav #define HAS_CREATE_TOKEN 1
80d0c8c0bcSDag-Erling Smørgrav #define HAS_NTSEC_BY_DEFAULT 2
8152028650SDag-Erling Smørgrav #define HAS_CREATE_TOKEN_WO_NTSEC 3
82d0c8c0bcSDag-Erling Smørgrav 
83d95e11bfSDag-Erling Smørgrav static int
84d95e11bfSDag-Erling Smørgrav has_capability(int what)
85d0c8c0bcSDag-Erling Smørgrav {
86d0c8c0bcSDag-Erling Smørgrav 	static int inited;
87d0c8c0bcSDag-Erling Smørgrav 	static int has_create_token;
88d0c8c0bcSDag-Erling Smørgrav 	static int has_ntsec_by_default;
8952028650SDag-Erling Smørgrav 	static int has_create_token_wo_ntsec;
90d0c8c0bcSDag-Erling Smørgrav 
91d95e11bfSDag-Erling Smørgrav 	/*
92d95e11bfSDag-Erling Smørgrav 	 * has_capability() basically calls uname() and checks if
93d95e11bfSDag-Erling Smørgrav 	 * specific capabilities of Cygwin can be evaluated from that.
94d95e11bfSDag-Erling Smørgrav 	 * This simplifies the calling functions which only have to ask
95d95e11bfSDag-Erling Smørgrav 	 * for a capability using has_capability() instead of having
96d95e11bfSDag-Erling Smørgrav 	 * to figure that out by themselves.
97d95e11bfSDag-Erling Smørgrav 	 */
98d0c8c0bcSDag-Erling Smørgrav 	if (!inited) {
99d0c8c0bcSDag-Erling Smørgrav 		struct utsname uts;
100d0c8c0bcSDag-Erling Smørgrav 
101d0c8c0bcSDag-Erling Smørgrav 		if (!uname(&uts)) {
102d95e11bfSDag-Erling Smørgrav 			int major_high = 0, major_low = 0, minor = 0;
103d95e11bfSDag-Erling Smørgrav 			int api_major_version = 0, api_minor_version = 0;
104d0c8c0bcSDag-Erling Smørgrav 			char *c;
105d0c8c0bcSDag-Erling Smørgrav 
106d0c8c0bcSDag-Erling Smørgrav 			sscanf(uts.release, "%d.%d.%d", &major_high,
107d0c8c0bcSDag-Erling Smørgrav 			    &major_low, &minor);
108d95e11bfSDag-Erling Smørgrav 			if ((c = strchr(uts.release, '(')) != NULL) {
109d0c8c0bcSDag-Erling Smørgrav 				sscanf(c + 1, "%d.%d", &api_major_version,
110d0c8c0bcSDag-Erling Smørgrav 				    &api_minor_version);
111d95e11bfSDag-Erling Smørgrav 			}
112d0c8c0bcSDag-Erling Smørgrav 			if (major_high > 1 ||
113d0c8c0bcSDag-Erling Smørgrav 			    (major_high == 1 && (major_low > 3 ||
114d0c8c0bcSDag-Erling Smørgrav 			    (major_low == 3 && minor >= 2))))
115d0c8c0bcSDag-Erling Smørgrav 				has_create_token = 1;
116d0c8c0bcSDag-Erling Smørgrav 			if (api_major_version > 0 || api_minor_version >= 56)
117d0c8c0bcSDag-Erling Smørgrav 				has_ntsec_by_default = 1;
11852028650SDag-Erling Smørgrav 			if (major_high > 1 ||
11952028650SDag-Erling Smørgrav 			    (major_high == 1 && major_low >= 5))
12052028650SDag-Erling Smørgrav 				has_create_token_wo_ntsec = 1;
121d0c8c0bcSDag-Erling Smørgrav 			inited = 1;
122d0c8c0bcSDag-Erling Smørgrav 		}
123d0c8c0bcSDag-Erling Smørgrav 	}
124d0c8c0bcSDag-Erling Smørgrav 	switch (what) {
125d0c8c0bcSDag-Erling Smørgrav 	case HAS_CREATE_TOKEN:
126d95e11bfSDag-Erling Smørgrav 		return (has_create_token);
127d0c8c0bcSDag-Erling Smørgrav 	case HAS_NTSEC_BY_DEFAULT:
128d95e11bfSDag-Erling Smørgrav 		return (has_ntsec_by_default);
12952028650SDag-Erling Smørgrav 	case HAS_CREATE_TOKEN_WO_NTSEC:
13052028650SDag-Erling Smørgrav 		return (has_create_token_wo_ntsec);
131d0c8c0bcSDag-Erling Smørgrav 	}
132d95e11bfSDag-Erling Smørgrav 	return (0);
133d0c8c0bcSDag-Erling Smørgrav }
134d0c8c0bcSDag-Erling Smørgrav 
135d95e11bfSDag-Erling Smørgrav int
136d95e11bfSDag-Erling Smørgrav check_nt_auth(int pwd_authenticated, struct passwd *pw)
13783d2307dSDag-Erling Smørgrav {
13883d2307dSDag-Erling Smørgrav 	/*
13983d2307dSDag-Erling Smørgrav 	* The only authentication which is able to change the user
14083d2307dSDag-Erling Smørgrav 	* context on NT systems is the password authentication. So
14183d2307dSDag-Erling Smørgrav 	* we deny all requsts for changing the user context if another
14283d2307dSDag-Erling Smørgrav 	* authentication method is used.
14383d2307dSDag-Erling Smørgrav 	*
14483d2307dSDag-Erling Smørgrav 	* This doesn't apply to Cygwin versions >= 1.3.2 anymore which
14583d2307dSDag-Erling Smørgrav 	* uses the undocumented NtCreateToken() call to create a user
14683d2307dSDag-Erling Smørgrav 	* token if the process has the appropriate privileges and if
14783d2307dSDag-Erling Smørgrav 	* CYGWIN ntsec setting is on.
14883d2307dSDag-Erling Smørgrav 	*/
14983d2307dSDag-Erling Smørgrav 	static int has_create_token = -1;
15083d2307dSDag-Erling Smørgrav 
15183d2307dSDag-Erling Smørgrav 	if (pw == NULL)
15283d2307dSDag-Erling Smørgrav 		return 0;
15383d2307dSDag-Erling Smørgrav 	if (is_winnt) {
15483d2307dSDag-Erling Smørgrav 		if (has_create_token < 0) {
15583d2307dSDag-Erling Smørgrav 			char *cygwin = getenv("CYGWIN");
15683d2307dSDag-Erling Smørgrav 
15783d2307dSDag-Erling Smørgrav 			has_create_token = 0;
158d0c8c0bcSDag-Erling Smørgrav 			if (has_capability(HAS_CREATE_TOKEN) &&
159d0c8c0bcSDag-Erling Smørgrav 			    (ntsec_on(cygwin) ||
160d0c8c0bcSDag-Erling Smørgrav 			    (has_capability(HAS_NTSEC_BY_DEFAULT) &&
16152028650SDag-Erling Smørgrav 			     !ntsec_off(cygwin)) ||
16252028650SDag-Erling Smørgrav 			     has_capability(HAS_CREATE_TOKEN_WO_NTSEC)))
16383d2307dSDag-Erling Smørgrav 				has_create_token = 1;
16483d2307dSDag-Erling Smørgrav 		}
16583d2307dSDag-Erling Smørgrav 		if (has_create_token < 1 &&
16683d2307dSDag-Erling Smørgrav 		    !pwd_authenticated && geteuid() != pw->pw_uid)
167d95e11bfSDag-Erling Smørgrav 			return (0);
16883d2307dSDag-Erling Smørgrav 	}
169d95e11bfSDag-Erling Smørgrav 	return (1);
17083d2307dSDag-Erling Smørgrav }
17183d2307dSDag-Erling Smørgrav 
172d95e11bfSDag-Erling Smørgrav int
173d95e11bfSDag-Erling Smørgrav check_ntsec(const char *filename)
17483d2307dSDag-Erling Smørgrav {
17583d2307dSDag-Erling Smørgrav 	char *cygwin;
176d95e11bfSDag-Erling Smørgrav 	int allow_ntea = 0, allow_ntsec = 0;
17783d2307dSDag-Erling Smørgrav 	struct statfs fsstat;
17883d2307dSDag-Erling Smørgrav 
17983d2307dSDag-Erling Smørgrav 	/* Windows 95/98/ME don't support file system security at all. */
18083d2307dSDag-Erling Smørgrav 	if (!is_winnt)
181d95e11bfSDag-Erling Smørgrav 		return (0);
18283d2307dSDag-Erling Smørgrav 
18383d2307dSDag-Erling Smørgrav 	/* Evaluate current CYGWIN settings. */
18483d2307dSDag-Erling Smørgrav 	cygwin = getenv("CYGWIN");
18583d2307dSDag-Erling Smørgrav 	allow_ntea = ntea_on(cygwin);
186d0c8c0bcSDag-Erling Smørgrav 	allow_ntsec = ntsec_on(cygwin) ||
187d95e11bfSDag-Erling Smørgrav 	    (has_capability(HAS_NTSEC_BY_DEFAULT) && !ntsec_off(cygwin));
18883d2307dSDag-Erling Smørgrav 
18983d2307dSDag-Erling Smørgrav 	/*
19083d2307dSDag-Erling Smørgrav 	 * `ntea' is an emulation of POSIX attributes. It doesn't support
19183d2307dSDag-Erling Smørgrav 	 * real file level security as ntsec on NTFS file systems does
19283d2307dSDag-Erling Smørgrav 	 * but it supports FAT filesystems. `ntea' is minimum requirement
19383d2307dSDag-Erling Smørgrav 	 * for security checks.
19483d2307dSDag-Erling Smørgrav 	 */
19583d2307dSDag-Erling Smørgrav 	if (allow_ntea)
196d95e11bfSDag-Erling Smørgrav 		return (1);
19783d2307dSDag-Erling Smørgrav 
19883d2307dSDag-Erling Smørgrav 	/*
19983d2307dSDag-Erling Smørgrav 	 * Retrieve file system flags. In Cygwin, file system flags are
20083d2307dSDag-Erling Smørgrav 	 * copied to f_type which has no meaning in Win32 itself.
20183d2307dSDag-Erling Smørgrav 	 */
20283d2307dSDag-Erling Smørgrav 	if (statfs(filename, &fsstat))
203d95e11bfSDag-Erling Smørgrav 		return (1);
20483d2307dSDag-Erling Smørgrav 
20583d2307dSDag-Erling Smørgrav 	/*
20683d2307dSDag-Erling Smørgrav 	 * Only file systems supporting ACLs are able to set permissions.
20783d2307dSDag-Erling Smørgrav 	 * `ntsec' is the setting in Cygwin which switches using of NTFS
20883d2307dSDag-Erling Smørgrav 	 * ACLs to support POSIX permissions on files.
20983d2307dSDag-Erling Smørgrav 	 */
21083d2307dSDag-Erling Smørgrav 	if (fsstat.f_type & FS_PERSISTENT_ACLS)
211d95e11bfSDag-Erling Smørgrav 		return (allow_ntsec);
21283d2307dSDag-Erling Smørgrav 
213d95e11bfSDag-Erling Smørgrav 	return (0);
21483d2307dSDag-Erling Smørgrav }
21583d2307dSDag-Erling Smørgrav 
216d95e11bfSDag-Erling Smørgrav void
217d95e11bfSDag-Erling Smørgrav register_9x_service(void)
21883d2307dSDag-Erling Smørgrav {
21983d2307dSDag-Erling Smørgrav         HINSTANCE kerneldll;
22083d2307dSDag-Erling Smørgrav         DWORD (*RegisterServiceProcess)(DWORD, DWORD);
22183d2307dSDag-Erling Smørgrav 
22283d2307dSDag-Erling Smørgrav 	/* The service register mechanism in 9x/Me is pretty different from
22383d2307dSDag-Erling Smørgrav 	 * NT/2K/XP.  In NT/2K/XP we're using a special service starter
22483d2307dSDag-Erling Smørgrav 	 * application to register and control sshd as service.  This method
22583d2307dSDag-Erling Smørgrav 	 * doesn't play nicely with 9x/Me.  For that reason we register here
22683d2307dSDag-Erling Smørgrav 	 * as service when running under 9x/Me.  This function is only called
22783d2307dSDag-Erling Smørgrav 	 * by the child sshd when it's going to daemonize.
22883d2307dSDag-Erling Smørgrav 	 */
22983d2307dSDag-Erling Smørgrav 	if (is_winnt)
23083d2307dSDag-Erling Smørgrav 		return;
23183d2307dSDag-Erling Smørgrav 	if (!(kerneldll = LoadLibrary("KERNEL32.DLL")))
23283d2307dSDag-Erling Smørgrav 		return;
23383d2307dSDag-Erling Smørgrav 	if (!(RegisterServiceProcess = (DWORD (*)(DWORD, DWORD))
23483d2307dSDag-Erling Smørgrav 		GetProcAddress(kerneldll, "RegisterServiceProcess")))
23583d2307dSDag-Erling Smørgrav 		return;
23683d2307dSDag-Erling Smørgrav 	RegisterServiceProcess(0, 1);
23783d2307dSDag-Erling Smørgrav }
23883d2307dSDag-Erling Smørgrav 
2395e8dbd04SDag-Erling Smørgrav #define NL(x) x, (sizeof (x) - 1)
2405e8dbd04SDag-Erling Smørgrav #define WENV_SIZ (sizeof (wenv_arr) / sizeof (wenv_arr[0]))
2415e8dbd04SDag-Erling Smørgrav 
2425e8dbd04SDag-Erling Smørgrav static struct wenv {
2435e8dbd04SDag-Erling Smørgrav 	const char *name;
2445e8dbd04SDag-Erling Smørgrav 	size_t namelen;
2455e8dbd04SDag-Erling Smørgrav } wenv_arr[] = {
2465e8dbd04SDag-Erling Smørgrav 	{ NL("ALLUSERSPROFILE=") },
2475e8dbd04SDag-Erling Smørgrav 	{ NL("COMMONPROGRAMFILES=") },
2485e8dbd04SDag-Erling Smørgrav 	{ NL("COMPUTERNAME=") },
2495e8dbd04SDag-Erling Smørgrav 	{ NL("COMSPEC=") },
2505e8dbd04SDag-Erling Smørgrav 	{ NL("NUMBER_OF_PROCESSORS=") },
2515e8dbd04SDag-Erling Smørgrav 	{ NL("OS=") },
2525e8dbd04SDag-Erling Smørgrav 	{ NL("PATH=") },
2535e8dbd04SDag-Erling Smørgrav 	{ NL("PATHEXT=") },
2545e8dbd04SDag-Erling Smørgrav 	{ NL("PROCESSOR_ARCHITECTURE=") },
2555e8dbd04SDag-Erling Smørgrav 	{ NL("PROCESSOR_IDENTIFIER=") },
2565e8dbd04SDag-Erling Smørgrav 	{ NL("PROCESSOR_LEVEL=") },
2575e8dbd04SDag-Erling Smørgrav 	{ NL("PROCESSOR_REVISION=") },
2585e8dbd04SDag-Erling Smørgrav 	{ NL("PROGRAMFILES=") },
2595e8dbd04SDag-Erling Smørgrav 	{ NL("SYSTEMDRIVE=") },
2605e8dbd04SDag-Erling Smørgrav 	{ NL("SYSTEMROOT=") },
2615e8dbd04SDag-Erling Smørgrav 	{ NL("TMP=") },
2625e8dbd04SDag-Erling Smørgrav 	{ NL("TEMP=") },
2635e8dbd04SDag-Erling Smørgrav 	{ NL("WINDIR=") },
2645e8dbd04SDag-Erling Smørgrav };
2655e8dbd04SDag-Erling Smørgrav 
2665e8dbd04SDag-Erling Smørgrav char **
2675e8dbd04SDag-Erling Smørgrav fetch_windows_environment(void)
2685e8dbd04SDag-Erling Smørgrav {
2695e8dbd04SDag-Erling Smørgrav 	char **e, **p;
2705e8dbd04SDag-Erling Smørgrav 	int i, idx = 0;
2715e8dbd04SDag-Erling Smørgrav 
2725e8dbd04SDag-Erling Smørgrav 	p = xmalloc(WENV_SIZ * sizeof(char *));
2735e8dbd04SDag-Erling Smørgrav 	for (e = environ; *e != NULL; ++e) {
2745e8dbd04SDag-Erling Smørgrav 		for (i = 0; i < WENV_SIZ; ++i) {
2755e8dbd04SDag-Erling Smørgrav 			if (!strncmp(*e, wenv_arr[i].name, wenv_arr[i].namelen))
2765e8dbd04SDag-Erling Smørgrav 				p[idx++] = *e;
2775e8dbd04SDag-Erling Smørgrav 		}
2785e8dbd04SDag-Erling Smørgrav 	}
2795e8dbd04SDag-Erling Smørgrav 	p[idx] = NULL;
2805e8dbd04SDag-Erling Smørgrav 	return p;
2815e8dbd04SDag-Erling Smørgrav }
2825e8dbd04SDag-Erling Smørgrav 
2835e8dbd04SDag-Erling Smørgrav void
2845e8dbd04SDag-Erling Smørgrav free_windows_environment(char **p)
2855e8dbd04SDag-Erling Smørgrav {
2865e8dbd04SDag-Erling Smørgrav 	xfree(p);
2875e8dbd04SDag-Erling Smørgrav }
2885e8dbd04SDag-Erling Smørgrav 
28983d2307dSDag-Erling Smørgrav #endif /* HAVE_CYGWIN */
290