xref: /freebsd/crypto/openssh/openbsd-compat/bsd-cygwin_util.c (revision d95e11bf7e5a59b5c3f81bd8dfc2918ee7d3bada)
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 
32d95e11bfSDag-Erling Smørgrav RCSID("$Id: bsd-cygwin_util.c,v 1.11 2003/08/07 06:23:43 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>
4183d2307dSDag-Erling Smørgrav #define is_winnt       (GetVersion() < 0x80000000)
4283d2307dSDag-Erling Smørgrav 
4383d2307dSDag-Erling Smørgrav #define ntsec_on(c)	((c) && strstr((c),"ntsec") && !strstr((c),"nontsec"))
44d0c8c0bcSDag-Erling Smørgrav #define ntsec_off(c)	((c) && strstr((c),"nontsec"))
4583d2307dSDag-Erling Smørgrav #define ntea_on(c)	((c) && strstr((c),"ntea") && !strstr((c),"nontea"))
4683d2307dSDag-Erling Smørgrav 
4783d2307dSDag-Erling Smørgrav #if defined(open) && open == binary_open
4883d2307dSDag-Erling Smørgrav # undef open
4983d2307dSDag-Erling Smørgrav #endif
5083d2307dSDag-Erling Smørgrav #if defined(pipe) && open == binary_pipe
5183d2307dSDag-Erling Smørgrav # undef pipe
5283d2307dSDag-Erling Smørgrav #endif
5383d2307dSDag-Erling Smørgrav 
54d95e11bfSDag-Erling Smørgrav int
55d95e11bfSDag-Erling Smørgrav binary_open(const char *filename, int flags, ...)
5683d2307dSDag-Erling Smørgrav {
5783d2307dSDag-Erling Smørgrav 	va_list ap;
5883d2307dSDag-Erling Smørgrav 	mode_t mode;
5983d2307dSDag-Erling Smørgrav 
6083d2307dSDag-Erling Smørgrav 	va_start(ap, flags);
6183d2307dSDag-Erling Smørgrav 	mode = va_arg(ap, mode_t);
6283d2307dSDag-Erling Smørgrav 	va_end(ap);
63d95e11bfSDag-Erling Smørgrav 	return (open(filename, flags | O_BINARY, mode));
6483d2307dSDag-Erling Smørgrav }
6583d2307dSDag-Erling Smørgrav 
66d95e11bfSDag-Erling Smørgrav int
67d95e11bfSDag-Erling Smørgrav binary_pipe(int fd[2])
6883d2307dSDag-Erling Smørgrav {
6983d2307dSDag-Erling Smørgrav 	int ret = pipe(fd);
7083d2307dSDag-Erling Smørgrav 
7183d2307dSDag-Erling Smørgrav 	if (!ret) {
7283d2307dSDag-Erling Smørgrav 		setmode(fd[0], O_BINARY);
7383d2307dSDag-Erling Smørgrav 		setmode(fd[1], O_BINARY);
7483d2307dSDag-Erling Smørgrav 	}
75d95e11bfSDag-Erling Smørgrav 	return (ret);
7683d2307dSDag-Erling Smørgrav }
7783d2307dSDag-Erling Smørgrav 
78d0c8c0bcSDag-Erling Smørgrav #define HAS_CREATE_TOKEN 1
79d0c8c0bcSDag-Erling Smørgrav #define HAS_NTSEC_BY_DEFAULT 2
80d0c8c0bcSDag-Erling Smørgrav 
81d95e11bfSDag-Erling Smørgrav static int
82d95e11bfSDag-Erling Smørgrav has_capability(int what)
83d0c8c0bcSDag-Erling Smørgrav {
84d0c8c0bcSDag-Erling Smørgrav 	static int inited;
85d0c8c0bcSDag-Erling Smørgrav 	static int has_create_token;
86d0c8c0bcSDag-Erling Smørgrav 	static int has_ntsec_by_default;
87d0c8c0bcSDag-Erling Smørgrav 
88d95e11bfSDag-Erling Smørgrav 	/*
89d95e11bfSDag-Erling Smørgrav 	 * has_capability() basically calls uname() and checks if
90d95e11bfSDag-Erling Smørgrav 	 * specific capabilities of Cygwin can be evaluated from that.
91d95e11bfSDag-Erling Smørgrav 	 * This simplifies the calling functions which only have to ask
92d95e11bfSDag-Erling Smørgrav 	 * for a capability using has_capability() instead of having
93d95e11bfSDag-Erling Smørgrav 	 * to figure that out by themselves.
94d95e11bfSDag-Erling Smørgrav 	 */
95d0c8c0bcSDag-Erling Smørgrav 	if (!inited) {
96d0c8c0bcSDag-Erling Smørgrav 		struct utsname uts;
97d0c8c0bcSDag-Erling Smørgrav 		char *c;
98d0c8c0bcSDag-Erling Smørgrav 
99d0c8c0bcSDag-Erling Smørgrav 		if (!uname(&uts)) {
100d95e11bfSDag-Erling Smørgrav 			int major_high = 0, major_low = 0, minor = 0;
101d95e11bfSDag-Erling Smørgrav 			int api_major_version = 0, api_minor_version = 0;
102d0c8c0bcSDag-Erling Smørgrav 			char *c;
103d0c8c0bcSDag-Erling Smørgrav 
104d0c8c0bcSDag-Erling Smørgrav 			sscanf(uts.release, "%d.%d.%d", &major_high,
105d0c8c0bcSDag-Erling Smørgrav 			    &major_low, &minor);
106d95e11bfSDag-Erling Smørgrav 			if ((c = strchr(uts.release, '(')) != NULL) {
107d0c8c0bcSDag-Erling Smørgrav 				sscanf(c + 1, "%d.%d", &api_major_version,
108d0c8c0bcSDag-Erling Smørgrav 				    &api_minor_version);
109d95e11bfSDag-Erling Smørgrav 			}
110d0c8c0bcSDag-Erling Smørgrav 			if (major_high > 1 ||
111d0c8c0bcSDag-Erling Smørgrav 			    (major_high == 1 && (major_low > 3 ||
112d0c8c0bcSDag-Erling Smørgrav 			    (major_low == 3 && minor >= 2))))
113d0c8c0bcSDag-Erling Smørgrav 				has_create_token = 1;
114d0c8c0bcSDag-Erling Smørgrav 			if (api_major_version > 0 || api_minor_version >= 56)
115d0c8c0bcSDag-Erling Smørgrav 				has_ntsec_by_default = 1;
116d0c8c0bcSDag-Erling Smørgrav 			inited = 1;
117d0c8c0bcSDag-Erling Smørgrav 		}
118d0c8c0bcSDag-Erling Smørgrav 	}
119d0c8c0bcSDag-Erling Smørgrav 	switch (what) {
120d0c8c0bcSDag-Erling Smørgrav 	case HAS_CREATE_TOKEN:
121d95e11bfSDag-Erling Smørgrav 		return (has_create_token);
122d0c8c0bcSDag-Erling Smørgrav 	case HAS_NTSEC_BY_DEFAULT:
123d95e11bfSDag-Erling Smørgrav 		return (has_ntsec_by_default);
124d0c8c0bcSDag-Erling Smørgrav 	}
125d95e11bfSDag-Erling Smørgrav 	return (0);
126d0c8c0bcSDag-Erling Smørgrav }
127d0c8c0bcSDag-Erling Smørgrav 
128d95e11bfSDag-Erling Smørgrav int
129d95e11bfSDag-Erling Smørgrav check_nt_auth(int pwd_authenticated, struct passwd *pw)
13083d2307dSDag-Erling Smørgrav {
13183d2307dSDag-Erling Smørgrav 	/*
13283d2307dSDag-Erling Smørgrav 	* The only authentication which is able to change the user
13383d2307dSDag-Erling Smørgrav 	* context on NT systems is the password authentication. So
13483d2307dSDag-Erling Smørgrav 	* we deny all requsts for changing the user context if another
13583d2307dSDag-Erling Smørgrav 	* authentication method is used.
13683d2307dSDag-Erling Smørgrav 	*
13783d2307dSDag-Erling Smørgrav 	* This doesn't apply to Cygwin versions >= 1.3.2 anymore which
13883d2307dSDag-Erling Smørgrav 	* uses the undocumented NtCreateToken() call to create a user
13983d2307dSDag-Erling Smørgrav 	* token if the process has the appropriate privileges and if
14083d2307dSDag-Erling Smørgrav 	* CYGWIN ntsec setting is on.
14183d2307dSDag-Erling Smørgrav 	*/
14283d2307dSDag-Erling Smørgrav 	static int has_create_token = -1;
14383d2307dSDag-Erling Smørgrav 
14483d2307dSDag-Erling Smørgrav 	if (pw == NULL)
14583d2307dSDag-Erling Smørgrav 		return 0;
14683d2307dSDag-Erling Smørgrav 	if (is_winnt) {
14783d2307dSDag-Erling Smørgrav 		if (has_create_token < 0) {
14883d2307dSDag-Erling Smørgrav 			char *cygwin = getenv("CYGWIN");
14983d2307dSDag-Erling Smørgrav 
15083d2307dSDag-Erling Smørgrav 			has_create_token = 0;
151d0c8c0bcSDag-Erling Smørgrav 			if (has_capability(HAS_CREATE_TOKEN) &&
152d0c8c0bcSDag-Erling Smørgrav 			    (ntsec_on(cygwin) ||
153d0c8c0bcSDag-Erling Smørgrav 			    (has_capability(HAS_NTSEC_BY_DEFAULT) &&
154d0c8c0bcSDag-Erling Smørgrav 			    !ntsec_off(cygwin))))
15583d2307dSDag-Erling Smørgrav 				has_create_token = 1;
15683d2307dSDag-Erling Smørgrav 		}
15783d2307dSDag-Erling Smørgrav 		if (has_create_token < 1 &&
15883d2307dSDag-Erling Smørgrav 		    !pwd_authenticated && geteuid() != pw->pw_uid)
159d95e11bfSDag-Erling Smørgrav 			return (0);
16083d2307dSDag-Erling Smørgrav 	}
161d95e11bfSDag-Erling Smørgrav 	return (1);
16283d2307dSDag-Erling Smørgrav }
16383d2307dSDag-Erling Smørgrav 
164d95e11bfSDag-Erling Smørgrav int
165d95e11bfSDag-Erling Smørgrav check_ntsec(const char *filename)
16683d2307dSDag-Erling Smørgrav {
16783d2307dSDag-Erling Smørgrav 	char *cygwin;
168d95e11bfSDag-Erling Smørgrav 	int allow_ntea = 0, allow_ntsec = 0;
16983d2307dSDag-Erling Smørgrav 	struct statfs fsstat;
17083d2307dSDag-Erling Smørgrav 
17183d2307dSDag-Erling Smørgrav 	/* Windows 95/98/ME don't support file system security at all. */
17283d2307dSDag-Erling Smørgrav 	if (!is_winnt)
173d95e11bfSDag-Erling Smørgrav 		return (0);
17483d2307dSDag-Erling Smørgrav 
17583d2307dSDag-Erling Smørgrav 	/* Evaluate current CYGWIN settings. */
17683d2307dSDag-Erling Smørgrav 	cygwin = getenv("CYGWIN");
17783d2307dSDag-Erling Smørgrav 	allow_ntea = ntea_on(cygwin);
178d0c8c0bcSDag-Erling Smørgrav 	allow_ntsec = ntsec_on(cygwin) ||
179d95e11bfSDag-Erling Smørgrav 	    (has_capability(HAS_NTSEC_BY_DEFAULT) && !ntsec_off(cygwin));
18083d2307dSDag-Erling Smørgrav 
18183d2307dSDag-Erling Smørgrav 	/*
18283d2307dSDag-Erling Smørgrav 	 * `ntea' is an emulation of POSIX attributes. It doesn't support
18383d2307dSDag-Erling Smørgrav 	 * real file level security as ntsec on NTFS file systems does
18483d2307dSDag-Erling Smørgrav 	 * but it supports FAT filesystems. `ntea' is minimum requirement
18583d2307dSDag-Erling Smørgrav 	 * for security checks.
18683d2307dSDag-Erling Smørgrav 	 */
18783d2307dSDag-Erling Smørgrav 	if (allow_ntea)
188d95e11bfSDag-Erling Smørgrav 		return (1);
18983d2307dSDag-Erling Smørgrav 
19083d2307dSDag-Erling Smørgrav 	/*
19183d2307dSDag-Erling Smørgrav 	 * Retrieve file system flags. In Cygwin, file system flags are
19283d2307dSDag-Erling Smørgrav 	 * copied to f_type which has no meaning in Win32 itself.
19383d2307dSDag-Erling Smørgrav 	 */
19483d2307dSDag-Erling Smørgrav 	if (statfs(filename, &fsstat))
195d95e11bfSDag-Erling Smørgrav 		return (1);
19683d2307dSDag-Erling Smørgrav 
19783d2307dSDag-Erling Smørgrav 	/*
19883d2307dSDag-Erling Smørgrav 	 * Only file systems supporting ACLs are able to set permissions.
19983d2307dSDag-Erling Smørgrav 	 * `ntsec' is the setting in Cygwin which switches using of NTFS
20083d2307dSDag-Erling Smørgrav 	 * ACLs to support POSIX permissions on files.
20183d2307dSDag-Erling Smørgrav 	 */
20283d2307dSDag-Erling Smørgrav 	if (fsstat.f_type & FS_PERSISTENT_ACLS)
203d95e11bfSDag-Erling Smørgrav 		return (allow_ntsec);
20483d2307dSDag-Erling Smørgrav 
205d95e11bfSDag-Erling Smørgrav 	return (0);
20683d2307dSDag-Erling Smørgrav }
20783d2307dSDag-Erling Smørgrav 
208d95e11bfSDag-Erling Smørgrav void
209d95e11bfSDag-Erling Smørgrav register_9x_service(void)
21083d2307dSDag-Erling Smørgrav {
21183d2307dSDag-Erling Smørgrav         HINSTANCE kerneldll;
21283d2307dSDag-Erling Smørgrav         DWORD (*RegisterServiceProcess)(DWORD, DWORD);
21383d2307dSDag-Erling Smørgrav 
21483d2307dSDag-Erling Smørgrav 	/* The service register mechanism in 9x/Me is pretty different from
21583d2307dSDag-Erling Smørgrav 	 * NT/2K/XP.  In NT/2K/XP we're using a special service starter
21683d2307dSDag-Erling Smørgrav 	 * application to register and control sshd as service.  This method
21783d2307dSDag-Erling Smørgrav 	 * doesn't play nicely with 9x/Me.  For that reason we register here
21883d2307dSDag-Erling Smørgrav 	 * as service when running under 9x/Me.  This function is only called
21983d2307dSDag-Erling Smørgrav 	 * by the child sshd when it's going to daemonize.
22083d2307dSDag-Erling Smørgrav 	 */
22183d2307dSDag-Erling Smørgrav 	if (is_winnt)
22283d2307dSDag-Erling Smørgrav 		return;
22383d2307dSDag-Erling Smørgrav 	if (!(kerneldll = LoadLibrary("KERNEL32.DLL")))
22483d2307dSDag-Erling Smørgrav 		return;
22583d2307dSDag-Erling Smørgrav 	if (!(RegisterServiceProcess = (DWORD (*)(DWORD, DWORD))
22683d2307dSDag-Erling Smørgrav 		GetProcAddress(kerneldll, "RegisterServiceProcess")))
22783d2307dSDag-Erling Smørgrav 		return;
22883d2307dSDag-Erling Smørgrav 	RegisterServiceProcess(0, 1);
22983d2307dSDag-Erling Smørgrav }
23083d2307dSDag-Erling Smørgrav 
23183d2307dSDag-Erling Smørgrav #endif /* HAVE_CYGWIN */
232