Chris, the Young One <cky@pobox.com> - Password auth fixes
Christos Zoulas <christos@zoulas.com> - Autoconf fixes
Chun-Chung Chen <cjj@u.washington.edu> - RPM fixes
+Corinna Vinschen <vinschen@cygnus.com> - Cygwin support
Dan Brosemer <odin@linuxfreak.com> - Autoconf support, build fixes
Darren Hall <dhall@virage.org> - AIX patches
David Agraz <dagraz@jahoopa.com> - Build fixes
[session.c]
set SSH_ORIGINAL_COMMAND; from Leakin@dfw.nostrum.com, bet@rahul.net
- (djm) Cleanup after import. Fix sftp-server compilation, Makefile
+ - (djm) Merge cygwin support from Corinna Vinschen <vinschen@cygnus.com>
+
20000903
- (djm) Fix Redhat init script
PERL=@PERL@
ENT=@ENT@
LDFLAGS=-L. @LDFLAGS@
+EXEEXT=@EXEEXT@
INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@
-TARGETS=ssh sshd ssh-add ssh-keygen ssh-agent scp sftp-server $(EXTRA_TARGETS)
+TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) $(EXTRA_TARGETS)
-LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dispatch.o dsa.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o util.o uuencode.o xmalloc.o
+LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o cygwin_util.o deattack.o dispatch.o dsa.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o util.o uuencode.o xmalloc.o
LIBOPENBSD_COMPAT_OBJS=bsd-arc4random.o bsd-base64.o bsd-bindresvport.o bsd-daemon.o bsd-inet_aton.o bsd-inet_ntoa.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-sigaction.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bsd-strsep.o fake-getaddrinfo.o fake-getnameinfo.o next-posix.o
$(AR) rv $@ $(LIBSSH_OBJS)
$(RANLIB) $@
-ssh: libopenbsd-compat.a libssh.a $(SSHOBJS)
+ssh$(EXEEXT): libopenbsd-compat.a libssh.a $(SSHOBJS)
$(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
-sshd: libssh.a libopenbsd-compat.a $(SSHDOBJS)
+sshd$(EXEEXT): libssh.a libopenbsd-compat.a $(SSHDOBJS)
$(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
-scp: libopenbsd-compat.a libssh.a scp.o
+scp$(EXEEXT): libopenbsd-compat.a libssh.a scp.o
$(LD) -o $@ scp.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
-ssh-add: libopenbsd-compat.a libssh.a ssh-add.o log-client.o
+ssh-add$(EXEEXT): libopenbsd-compat.a libssh.a ssh-add.o log-client.o
$(LD) -o $@ ssh-add.o log-client.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
-ssh-agent: libopenbsd-compat.a libssh.a ssh-agent.o log-client.o
+ssh-agent$(EXEEXT): libopenbsd-compat.a libssh.a ssh-agent.o log-client.o
$(LD) -o $@ ssh-agent.o log-client.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
-ssh-keygen: libopenbsd-compat.a libssh.a ssh-keygen.o log-client.o
+ssh-keygen$(EXEEXT): libopenbsd-compat.a libssh.a ssh-keygen.o log-client.o
$(LD) -o $@ ssh-keygen.o log-client.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
-sftp-server: libopenbsd-compat.a libssh.a sftp-server.o log-server.o
+sftp-server$(EXEEXT): libopenbsd-compat.a libssh.a sftp-server.o log-server.o
$(LD) -o $@ sftp-server.o log-server.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
# test driver for the loginrec code - not built by default
$(INSTALL) -m 644 sshd.[08].out $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8
$(INSTALL) -m 644 sftp-server.[08].out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
-rm -f $(DESTDIR)$(bindir)/slogin
- ln -s ssh $(DESTDIR)$(bindir)/slogin
+ ln -s ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
ln -s ssh.1 $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
if [ ! -f $(DESTDIR)$(sysconfdir)/ssh_config -a ! -f $(DESTDIR)$(sysconfdir)/sshd_config ]; then \
$(INSTALL) -m 644 ssh_prng_cmds.out $(DESTDIR)$(sysconfdir)/ssh_prng_cmds; \
fi
-host-key: ssh-keygen
+host-key: ssh-keygen$(EXEEXT)
if [ -z "$(DESTDIR)" ] ; then \
if [ -f "$(DESTDIR)$(sysconfdir)/ssh_host_key" ] ; then \
echo "$(DESTDIR)$(sysconfdir)/ssh_host_key already exists, skipping." ; \
fi ; \
fi ;
-host-key-force: ssh-keygen
+host-key-force: ssh-keygen$(EXEEXT)
./ssh-keygen -b 1024 -f $(DESTDIR)$(sysconfdir)/ssh_host_key -N ""
./ssh-keygen -d -f $(DESTDIR)$(sysconfdir)/ssh_host_dsa_key -N ""
-rmdir $(DESTDIR)$(libexecdir)
uninstall:
- -rm -f $(DESTDIR)$(bindir)/ssh
- -rm -f $(DESTDIR)$(bindir)/scp
- -rm -f $(DESTDIR)$(bindir)/ssh-add
- -rm -f $(DESTDIR)$(bindir)/ssh-agent
- -rm -f $(DESTDIR)$(bindir)/ssh-keygen
- -rm -f $(DESTDIR)$(sbindir)/sshd
+ -rm -f $(DESTDIR)$(bindir)/ssh$(EXEEXT)
+ -rm -f $(DESTDIR)$(bindir)/scp$(EXEEXT)
+ -rm -f $(DESTDIR)$(bindir)/ssh-add$(EXEEXT)
+ -rm -f $(DESTDIR)$(bindir)/ssh-agent$(EXEEXT)
+ -rm -f $(DESTDIR)$(bindir)/ssh-keygen$(EXEEXT)
+ -rm -f $(DESTDIR)$(sbindir)/sshd$(EXEEXT)
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1
-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1
/* Define if your snprintf is busted */
#undef BROKEN_SNPRINTF
+/* Define if you are on Cygwin */
+#undef HAVE_CYGWIN
+
/* Define if you are on NeXT */
#undef HAVE_NEXT
/* getaddrinfo is broken (if present) */
#undef BROKEN_GETADDRINFO
+/* vhangup is broken (if present) */
+#undef BROKEN_VHANGUP
+
/* Workaround more Linux IPv6 quirks */
#undef DONT_TRY_OTHER_AF
# include "md5crypt.h"
#endif /* defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT) */
+#ifdef HAVE_CYGWIN
+#undef ERROR
+#include <windows.h>
+#include <sys/cygwin.h>
+#define is_winnt (GetVersion() < 0x80000000)
+#endif
+
/*
* Tries to authenticate the user using password. Returns true if
* authentication succeeds.
/* deny if no user. */
if (pw == NULL)
return 0;
+#ifndef HAVE_CYGWIN
if (pw->pw_uid == 0 && options.permit_root_login == 2)
return 0;
+#endif
+#ifdef HAVE_CYGWIN
+ /*
+ * Empty password is only possible on NT if the user has _really_
+ * an empty password and authentication is done, though.
+ */
+ if (!is_winnt)
+#endif
if (*password == '\0' && options.permit_empty_passwd == 0)
return 0;
+#ifdef HAVE_CYGWIN
+ if (is_winnt) {
+ HANDLE hToken = cygwin_logon_user(pw, password);
+
+ if (hToken == INVALID_HANDLE_VALUE)
+ return 0;
+ cygwin_set_impersonation_token(hToken);
+ return 1;
+ }
+#endif
+
#ifdef SKEY
if (options.skey_authentication == 1) {
int ret = auth_skey_password(pw, password);
# include <siad.h>
#endif
+#ifdef HAVE_CYGWIN
+#include <windows.h>
+#define is_winnt (GetVersion() < 0x80000000)
+#endif
+
/* import */
extern ServerOptions options;
extern char *forced_command;
break;
}
+#ifdef HAVE_CYGWIN
+ /*
+ * The only authentication which is able to change the user
+ * context on NT systems is the password authentication. So
+ * we deny all requsts for changing the user context if another
+ * authentication method is used.
+ * This may change in future when a special openssh
+ * subauthentication package is available.
+ */
+ if (is_winnt && type != SSH_CMSG_AUTH_PASSWORD &&
+ authenticated && geteuid() != pw->pw_uid) {
+ packet_disconnect("Authentication rejected for uid %d.",
+ (int) pw->pw_uid);
+ authenticated = 0;
+ }
+#endif
+
/*
* Check if the user is logging in as root and root logins
* are disallowed.
start_pam(pw);
#endif
+#ifndef HAVE_CYGWIN
/*
* If we are not running as root, the user must have the same uid as
* the server.
+ * Rule not valid on Windows systems.
*/
if (getuid() != 0 && pw->pw_uid != getuid())
packet_disconnect("Cannot change user when server not running as root.");
+#endif
debug("Attempting authentication for %.100s.", pw->pw_name);
if (fd < 0)
return 0;
- /* check owner and modes */
+#ifndef HAVE_CYGWIN
+ /*
+ * check owner and modes.
+ * This won't work on Windows under all circumstances so we drop
+ * that check for now.
+ */
if (fstat(fd, &st) < 0 ||
(st.st_uid != 0 && st.st_uid != getuid()) ||
(st.st_mode & 077) != 0) {
error("It is recommended that your private key files are NOT accessible by others.");
return 0;
}
+#endif
switch (key->type) {
case KEY_RSA:
if (key->rsa->e != NULL) {
case 0:
break;
default:
+#ifdef HAVE_CYGWIN
+ /*
+ * This sleep avoids a race condition which kills the
+ * child process if parent is started by a NT/W2K service.
+ */
+ sleep(1);
+#endif
_exit(0);
}
static char rcsid[] = "$OpenBSD: mktemp.c,v 1.13 1998/06/30 23:03:13 deraadt Exp $";
#endif /* LIBC_SCCS and not lint */
+#ifdef HAVE_CYGWIN
+#define open binary_open
+extern int binary_open();
+#endif
+
static int _gettemp(char *, int *, int, int);
int
hostname = packet_get_string(NULL);
host_port = packet_get_int();
+#ifndef HAVE_CYGWIN
/*
* Check that an unprivileged user is not trying to forward a
* privileged port.
if (port < IPPORT_RESERVED && !is_root)
packet_disconnect("Requested forwarding of port %d but user is not root.",
port);
+#endif
/*
* Initiate forwarding,
*/
MANTYPE='$(CATMAN)'
mansubdir=cat
;;
+*-*-cygwin*)
+ LIBS="$LIBS /usr/lib/textmode.o"
+ AC_DEFINE(HAVE_CYGWIN)
+ AC_DEFINE(DISABLE_PAM)
+ AC_DEFINE(DISABLE_SHADOW)
+ AC_DEFINE(IPV4_DEFAULT)
+ AC_DEFINE(IP_TOS_IS_BROKEN)
+ AC_DEFINE(BROKEN_VHANGUP)
+ no_pam=1
+ no_libsocket=1
+ no_libnsl=1
+ ;;
*-*-hpux10*)
if test -z "$GCC"; then
CFLAGS="$CFLAGS -Ae"
AC_MSG_WARN([Please check and edit -blibpath in LDFLAGS in Makefile])
fi
+AC_EXEEXT
+
AC_OUTPUT(Makefile ssh_prng_cmds)
# Print summary of options
--- /dev/null
+/*
+ *
+ * cygwin_util.c
+ *
+ * Author: Corinna Vinschen <vinschen@cygnus.com>
+ *
+ * Copyright (c) 2000 Corinna Vinschen <vinschen@cygnus.com>, Duisburg, Germany
+ * All rights reserved
+ *
+ * Created: Sat Sep 02 12:17:00 2000 cv
+ *
+ * This file contains functions for forcing opened file descriptors to
+ * binary mode on Windows systems.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_CYGWIN
+#include <fcntl.h>
+#include <io.h>
+
+int binary_open(const char *filename, int flags, mode_t mode)
+{
+ return open(filename, flags | O_BINARY, mode);
+}
+
+int binary_pipe(int fd[2])
+{
+ int ret = pipe(fd);
+ if (!ret) {
+ setmode (fd[0], O_BINARY);
+ setmode (fd[1], O_BINARY);
+ }
+}
+#endif
# define atexit(a) on_exit(a)
#endif /* !defined(HAVE_ATEXIT) && defined(HAVE_ON_EXIT) */
+#if defined(HAVE_VHANGUP) && !defined(BROKEN_VHANGUP)
+# define USE_VHANGUP
+#endif /* defined(HAVE_VHANGUP) && !defined(BROKEN_VHANGUP) */
+
/**
** login recorder definitions
**/
#include <sys/wait.h>
#include <sys/resource.h>
+#ifndef HAVE_CYGWIN
#include <netinet/tcp.h>
+#endif
#include <arpa/inet.h>
#include <netdb.h>
#include <grp.h>
#include <time.h>
#include <dirent.h>
+#ifdef HAVE_CYGWIN
+#include <getopt.h>
+#endif
#ifdef HAVE_BSTRING_H
# include <bstring.h>
*/
/* #define USE_PIPES 1 */
+#ifdef HAVE_CYGWIN
+#define open binary_open
+#define pipe binary_pipe
+extern int binary_open();
+extern int binary_pipe();
+#endif
+
#endif /* INCLUDES_H */
int
login_write (struct logininfo *li)
{
+#ifndef HAVE_CYGWIN
if ((int)geteuid() != 0) {
log("Attempt to write login records by non-root user (aborting)");
return 1;
}
+#endif
/* set the timestamp */
login_set_current_time(li);
close(*ptyfd);
return 0;
}
+#ifndef HAVE_CYGWIN
/* Push the appropriate streams modules, as described in Solaris pts(7). */
if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
error("ioctl I_PUSH ptem: %.100s", strerror(errno));
#ifndef _HPUX_SOURCE
if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
error("ioctl I_PUSH ttcompat: %.100s", strerror(errno));
+#endif
#endif
return 1;
#else /* HAVE_DEV_PTMX */
pty_make_controlling_tty(int *ttyfd, const char *ttyname)
{
int fd;
-#ifdef HAVE_VHANGUP
+#ifdef USE_VHANGUP
void *old;
-#endif /* HAVE_VHANGUP */
+#endif /* USE_VHANGUP */
/* First disconnect from the old controlling tty. */
#ifdef TIOCNOTTY
*/
ioctl(*ttyfd, TIOCSCTTY, NULL);
#endif /* TIOCSCTTY */
-#ifdef HAVE_VHANGUP
+#ifdef USE_VHANGUP
old = signal(SIGHUP, SIG_IGN);
vhangup();
signal(SIGHUP, old);
-#endif /* HAVE_VHANGUP */
+#endif /* USE_VHANGUP */
fd = open(ttyname, O_RDWR);
if (fd < 0) {
error("%.100s: %.100s", ttyname, strerror(errno));
} else {
-#ifdef HAVE_VHANGUP
+#ifdef USE_VHANGUP
close(*ttyfd);
*ttyfd = fd;
-#else /* HAVE_VHANGUP */
+#else /* USE_VHANGUP */
close(fd);
-#endif /* HAVE_VHANGUP */
+#endif /* USE_VHANGUP */
}
/* Verify that we now have a controlling tty. */
fd = open("/dev/tty", O_WRONLY);
u_short host_port)
{
Forward *fwd;
+#ifndef HAVE_CYGWIN
extern uid_t original_real_uid;
if (port < IPPORT_RESERVED && original_real_uid != 0)
fatal("Privileged ports can only be forwarded by root.\n");
+#endif
if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
fwd = &options->local_forwards[options->num_local_forwards++];
if (pgrp == -1)
pgrp = getpgrp();
+#ifdef HAVE_CYGWIN
+ /*
+ * Cygwin only supports tcgetpgrp() for getting the controlling tty
+ * currently.
+ */
+ return ((ctty_pgrp = tcgetpgrp(STDOUT_FILENO)) != -1 &&
+ ctty_pgrp == pgrp);
+#else
return ((ioctl(STDOUT_FILENO, TIOCGPGRP, &ctty_pgrp) != -1 &&
ctty_pgrp == pgrp));
+#endif
}
void
# include <siad.h>
#endif
+#ifdef HAVE_CYGWIN
+#include <windows.h>
+#include <sys/cygwin.h>
+#define is_winnt (GetVersion() < 0x80000000)
+#endif
+
/* AIX limits */
#if defined(HAVE_GETUSERATTR) && !defined(S_UFSIZE_HARD) && defined(S_UFSIZE)
# define S_UFSIZE_HARD S_UFSIZE "_hard"
do_child(command, pw, NULL, s->display, s->auth_proto, s->auth_data, NULL);
/* NOTREACHED */
}
+#ifdef HAVE_CYGWIN
+ if (is_winnt)
+ cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
+#endif
if (pid < 0)
packet_disconnect("fork failed: %.100s", strerror(errno));
s->pid = pid;
s->auth_data, s->tty);
/* NOTREACHED */
}
+#ifdef HAVE_CYGWIN
+ if (is_winnt)
+ cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
+#endif
if (pid < 0)
packet_disconnect("fork failed: %.100s", strerror(errno));
s->pid = pid;
exit(1);
}
#else /* HAVE_OSF_SIA */
+#ifdef HAVE_CYGWIN
+ if (is_winnt) {
+#else
if (getuid() == 0 || geteuid() == 0) {
+#endif
# ifdef HAVE_GETUSERATTR
set_limits_from_userattr(pw->pw_name);
# endif /* HAVE_GETUSERATTR */
}
#endif /* HAVE_OSF_SIA */
+#ifdef HAVE_CYGWIN
+ if (is_winnt)
+#endif
if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
}
env = xmalloc(envsize * sizeof(char *));
env[0] = NULL;
+#ifdef HAVE_CYGWIN
+ /*
+ * The Windows environment contains some setting which are
+ * important for a running system. They must not be dropped.
+ */
+ {
+ char **ep;
+ for (ep = environ; *ep; ++ep) {
+ char *esp = strchr(*ep, '=');
+ *esp = '\0';
+ child_set_env(&env, &envsize, *ep, esp + 1);
+ *esp = '=';
+ }
+ }
+#endif
+
if (!options.use_login) {
/* Set basic environment. */
child_set_env(&env, &envsize, "USER", pw->pw_name);
(void) setusercontext(lc, pw, pw->pw_uid, LOGIN_SETPATH);
child_set_env(&env, &envsize, "PATH", getenv("PATH"));
#else
+#ifndef HAVE_CYGWIN
+ /*
+ * There's no standard path on Windows. The path contains
+ * important components pointing to the system directories,
+ * needed for loading shared libraries. So the path better
+ * remains intact here.
+ */
child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
+#endif
#endif
snprintf(buf, sizeof buf, "%.200s/%.50s",
"Running %.100s add %.100s %.100s %.100s\n",
options.xauth_location, display,
auth_proto, auth_data);
+#ifndef HAVE_CYGWIN
if (screen != NULL)
fprintf(stderr,
"Adding %.*s/unix%s %s %s\n",
(int)(screen-display), display,
screen, auth_proto, auth_data);
+#endif
}
snprintf(cmd, sizeof cmd, "%s -q -",
options.xauth_location);
if (f) {
fprintf(f, "add %s %s %s\n", display,
auth_proto, auth_data);
+#ifndef HAVE_CYGWIN
if (screen != NULL)
fprintf(f, "add %.*s/unix%s %s %s\n",
(int)(screen-display), display,
screen, auth_proto, auth_data);
+#endif
pclose(f);
} else {
fprintf(stderr, "Could not run %s\n",
original_real_uid = getuid();
original_effective_uid = geteuid();
+#ifndef HAVE_CYGWIN
/* If we are installed setuid root be careful to not drop core. */
if (original_real_uid != original_effective_uid) {
struct rlimit rlim;
if (setrlimit(RLIMIT_CORE, &rlim) < 0)
fatal("setrlimit failed: %.100s", strerror(errno));
}
+#endif
/*
* Use uid-swapping to give up root privileges for the duration of
* option processing. We will re-instantiate the rights when we are
cp = strrchr(av0, '/') + 1;
else
cp = av0;
+#ifdef HAVE_CYGWIN
+ if (strcasecmp(cp, "rsh") && strcasecmp(cp, "ssh") &&
+ strcasecmp(cp, "rlogin") && strcasecmp(cp, "slogin") &&
+ strcasecmp(cp, "remsh") &&
+ strcasecmp(cp, "rsh.exe") && strcasecmp(cp, "ssh.exe") &&
+ strcasecmp(cp, "rlogin.exe") && strcasecmp(cp, "slogin.exe") &&
+ strcasecmp(cp, "remsh.exe"))
+#else
if (strcmp(cp, "rsh") && strcmp(cp, "ssh") && strcmp(cp, "rlogin") &&
strcmp(cp, "slogin") && strcmp(cp, "remsh"))
+#endif
host = cp;
for (optind = 1; optind < ac; optind++) {
}
}
/* Disable rhosts authentication if not running as root. */
+#ifdef HAVE_CYGWIN
+ /* Ignore uid if running under Windows */
+ if (!options.use_privileged_port) {
+#else
if (original_effective_uid != 0 || !options.use_privileged_port) {
+#endif
options.rhosts_authentication = 0;
options.rhosts_rsa_authentication = 0;
}
/* Create a socket for connecting. */
sock = ssh_create_socket(original_real_uid,
+#ifdef HAVE_CYGWIN
+ !anonymous && port < IPPORT_RESERVED,
+#else
!anonymous && geteuid() == 0 && port < IPPORT_RESERVED,
+#endif
ai->ai_family);
if (sock < 0)
continue;
* fail if there already is a daemon, and this will
* overwrite any old pid in the file.
*/
- f = fopen(options.pid_file, "w");
+ f = fopen(options.pid_file, "wb");
if (f) {
fprintf(f, "%u\n", (unsigned int) getpid());
fclose(f);