Chapter 5 Developing Phase: Infrastructure Services

This chapter discusses the infrastructure services, which consist of the following features:

  • Security

  • Error handlers

  • Signals

  • Interprocess communication

  • Networking

  • Daemons and services

This chapter describes the implementation of the preceding services in Interix and provides a detailed comparison with the corresponding implementation in UNIX. Using the information provided in this chapter, you can identify the incompatibilities for your applications in these areas and also learn about the suggested replacement mechanisms in the Interix environment.

*

On This Page

Security Security
Error Handlers Error Handlers
Signals Signals
Interprocess Communication Interprocess Communication
Networking Networking
Daemons and Services Daemons and Services

Security

The UNIX and Microsoft® Windows® security models are quite different. Some of these differences are covered in the ”Architectural Differences Between UNIX and Interix” section in Chapter 1, “Introduction to Windows Services for UNIX 3.5” of this volume. The following subsections cover the differences between the various security models and describe how to modify your code to operate in Windows.

File System Security

Windows and UNIX both control the access to the files and directories.

In UNIX, the directory entry for each file or directory includes a bitmap of 12 bits, known as file-mode bits. Of these, three bits control access by the file's owner, three bits control access by the owner's primary group, and three control access by everyone else.

In Windows, files and directories on NTFS partitions are protected by a discretionary access control list (DACL) consisting of one or more access control entries (ACEs). Each entry assigns or denies permissions to a user or group, unlike with UNIX. However, the number of permissions that can be granted or denied is quite extensive and provides for a much finer degree of control over the access allowed to the user or group. In addition, ACEs can be added to the DACL for any number of users or groups, allowing the file's owner complete control over who can and cannot access the file.

Windows Services for UNIX 3.5 gives Windows users the ability to access files on UNIX-based servers using the network file system (NFS) protocol and, likewise, gives users of UNIX-based computers the ability to access files on Windows-based servers running Server for NFS. In addition, Interix provides a UNIX-like environment for Windows users, giving Interix users the ability to access and manage files on the Windows-based computer using UNIX tools. Because the same file, whether it is located on a Windows-based computer or a UNIX-based computer, can be accessed by both Windows and UNIX users, it is important to understand how UNIX file security and Windows file security interact through Windows Services for UNIX.

User-Level Security

Server for NFS security is a combination of Windows security and the security protocols that protect NFS shares. Both Windows security and NFS security control access to files by individual users, based on the account the user uses to log on. In addition, NFS security controls access to shared directories by specific client computers. Server for NFS enforces both types of access control. With Server for NFS, you can control access by users and groups to NFS resources. Controlled access is automatically enabled if Server for NFS is running on a Microsoft Windows Server™ 2003-based computer and the functional level of your domain or forest is Windows Server 2003. Otherwise, you must install Server for NFS Authentication on the primary and backup domain controllers of all domains containing users who might require access. (If you do not use Server for NFS Authentication and the functional level of your domain is not the Windows Server 2003 family, all users will access NFS resources as anonymous users.) You must also install User Name Mapping on one computer in your network to associate Windows user accounts with UNIX user accounts.

Process Level Security

Each Interix process has two process identifiers (PIDs). The reasons for the difference between the Interix PIDs and the Windows PIDs are as follows:

  • When an Interix process calls the exec() function, the new executable program must appear to all Interix processes as if it were the same process. For example, the PID for the new program must be the same as the PID for the old program that called the exec() function.

    However, Windows requires that the new process have a different PID than the previous one. When Windows starts the new program, it treats the new program as a new process. There is a very brief interval where both the old and the new processes exist at the same time. The old Windows PID is still in use when the new program is created. Therefore, the old Windows PID cannot be assigned to the new program.

  • While a Portable Operating System Interface (POSIX) process group exists, the Interix PID that corresponds to the POSIX group identifier (GID) cannot be reused.

    However, if a process with a particular Windows PID exits and then a new process is created, Windows can reuse that particular PID and assign it to the new process.

For situations in which programs need to use resources to which the current user does not have access, UNIX systems run the program as a specific user or group instead of as the current user or group. UNIX programs can use special permissions, called the setuid and setgid bits, on the executable file of the program.

According to the POSIX standard, the permissions for a file include bits to set a UID (setuid) and a GID (setgid). If either or both bits are set on a file and a process executes that file, the process runs with an identity based on the UID or GID of the file respectively.

When an Interix process executes a file that has the setuid or setgid bit set, Interix constructs local security tokens for the process with the privileges assigned to the owner (if setuid is set) or group (if setgid is set) of the file. Other computers on the network do not recognize these tokens because the tokens are local. Even if the file is owned by a member of the Domain Admins group, the process still does not have trusted access to other computers in the domain.

For example, if a process executes a program file that has its setuid bit set and the file is owned by a member of the Domain Admins group, and if that program attempts to change the password of a domain user, the attempt fails because the security tokens of the process are local and the program is not recognized by other systems in the domain. On the other hand, if the program attempts to change the password of a local user, the attempt succeeds because the owner of the file is a member of the Domain Admins group, which typically belongs to the Administrators group of the local computer.

On UNIX systems, the user and group owner of a program is often set to root, thereby allowing a nonroot user to run that program with root privileges. On Interix, the owner should be a Local Administrator or a member of the Domain Admins group.

To summarize, UNIX and Interix systems maintain at least two user and group IDs—the effective user ID and effective group ID, and the real user ID and real group ID. Most UNIX and Interix systems also support a saved set user ID and a saved set group ID.

Note As a security measure, Windows Services for UNIX 3.5 can be installed with the setuid capabilities disabled. Also, with Interix shell scripts, the setuid or setgid bits will be ignored. Any change in the file ownership will clear these bits so that the program cannot “accidentally” be run as the new owner.

To enable the execution of files with setuid or setgid mode bits set

  1. Insert the Windows Services for UNIX CD into the CD-ROM drive.

  2. At the command prompt, type:

        regini cd_drive:\setup\enablesetuid.ini 

        where cd_drive is the drive letter assigned to the CD-ROM drive.

        For the changes to take effect, you must restart your computer.

To restore default Interix behavior

  1. Insert the Windows Services for UNIX CD into the CD-ROM drive

  2. At the command prompt, type:

        regini cd_drive:\setup\disablesetuid.ini

Error Handlers

The Interix subsystem does not necessarily use the same error numbers that are used in traditional systems, hence you must always use the symbolic names defined in the errno.h file.

Almost all the system calls can return an error number in the external variable errno, which is defined in the errno.h file. When a system call detects an error, it returns an integer value indicating failure (usually -1) and sets the variable errno accordingly. Successful calls never set errno. After the errno is set, it remains the same until another error occurs. It should only be examined after an error.

When a system call returns -1, the calling function can interpret the failure and take action accordingly. Numerous system calls overload the meanings of these error numbers, so these meanings must be interpreted according to the type and circumstances of the call.

Interix uses POSIX UNIX error reporting from system calls by returning a non-zero integer, usually -1, and err, and assigning an integer value to variable errno. Refer to the Help manual of Windows Services for UNIX 3.5 for further information about err, verr, errx, verrx, warn, vwarn, warnx, vwarnx, errno, and strerror. The prototype of these functions is defined as follows.

void err (int eval, const char *fmt, ...)
void verr (int eval, const char *fmt, va_list args)
void errx (int eval, const char *fmt, ...)
void verrx (int eval, const char *fmt, va_list args)
void warn (const char *fmt, ...)
void vwarn (const char *fmt, va_list args)
void warnx (const char *fmt, ...)
void vwarnx (const char *fmt, va_list args)
char * strerror (int errnum)

It is up to the individual program (that makes a system call) to handle the error conditions from that call. For example, ksh assigns the built-in variable $? with the exit condition, and the value of errno is assigned to $ERRNO. The shell has some built-in error handling and is reported through stderr, but most of the error handling must be taken up by the programmer. You can get a string interpretation of the value of errno through strerror. Usage for other shells, commands, and programs will vary.

Signals

Signals are software interrupts that catch or indicate different types of events. This section describes the various signals and signal-handling routines. It also lists platform-specific signal functions that are not supported in Interix.Signal Handling.

Table 5.1. POSIX-Supported Signals

Signal Name

Description

Default Action/Effect

Number

SIGABRT

Abnormal termination

Terminate process

6

SIGALRM

Time-out alarm

Terminate process

14

SIGBUS

Bus error

Terminate process

10

SIGCHLD

Change in status of child

Ignore

18

SIGCONT

Continues stopped process

Ignore

25

SIGFPE

Floating-point exception

Terminate process

8

SIGHUP

Hang up

Terminate process

1

SIGILL

Illegal hardware instruction

Terminate process

4

SIGINT

Terminal interrupt character

Terminate process

2

SIGIO

I/O completion outstanding

Ignore

19

SIGKILL

Termination

Terminate process (cannot be caught or ignored)

9

SIGPIPE

Write to pipe with no readers

Terminate process

13

SIGPOLL

Pollable event (Sys V)–synonym of SIGIO

Ignore

22

SIGPROF

Profiling timer alarm

Terminate process

29

SIGQUIT

Terminal quit character

Terminate process

3

SIGSEGV

Invalid memory reference

Terminate process

11

SIGSTOP

Stop process

Stop process (cannot be caught or ignored)

23

SIGSYS

Invalid system call

Terminate process

12

SIGTERM

Software termination

Terminate process

15

SIGTRAP

Trace trap

Terminate process

5

SIGTSTP

Terminal stop character

Stop process

24

SIGTTIN

Background read from control TTY

Stop process

26

SIGTTOU

Background write to control TTY

Stop process

27

SIGURG

Urgent condition on socket

Ignore

21

SIGUSR1

User-defined signal

Terminate process

16

SIGUSR2

User-defined signal

Terminate process

17

SIGVTALRM

Virtual time alarm

Terminate process

28

SIGXCPU

CPU time limit exceeded

Terminate process

30

SIGXFSZ

File size limit exceeded

Terminate process

31

Interix supports most of the signal-handling functions. However, it does not support some nonstandard, platform-specific implementations, such as sigfpe and signal handling for specific SIGFPE codes.

Table 5.2 lists the platform-specific functions that are not supported by Interix along with the Interix substitutes to be used (if they exist).

Table 5.2. Platform-Specific Signal Functions Not Supported by Interix

Function name

Description

Suggested Interix replacement

bsd_signal

Simplified signal facilities.

Refer to sample code in "UNIX bsd_signal Code Replacement" immediately following this table.

getcontext

Gets current user context.

No support or equivalent in Interix.

gsignal

Software signals.

No support or equivalent in Interix.

makecontext

Manipulates user contexts.

No support or equivalent in Interix.

psiginfo

Software signals.

No support or equivalent in Interix.

sig2str

Translates the signal number signum to the signal name.

char *strsignal(int signal)

sigaltstack

Sets or gets signal alternative stack context.

No support or equivalent in Interix.

sigfpe

Handles signals for specific SIGFPE codes.

unsigned int _controlfp(unsigned int new, unsigned int mask)

siggetmask

Gets the current set of masked signals.

Use int sigprocmask(int how, const sigset_t *set, sigset_t *oset)

siginterrupt

Allows signals to interrupt functions.

Controlled by the SA_RESTART flag passed to sigaction().

sigsend

Sends a signal to a process or a group of processes.

No support or equivalent in Interix.

sigsendset

Sends a signal to a process or a group of processes.

No support or equivalent in Interix.

sigstack

Sets and/or gets alternative signal stack context.

No support or equivalent in Interix.

ssignal

Software signals.

No support or equivalent in Interix.

str2sig

Translates the signal name str to a signal number.

Write a simple table lookup routine. (See Table.)

Swapcontext

Manipulates user contexts.

No support or equivalent in Interix.

Psignal

System signal messages.

Maps closely to strsignal.

setcontext

Sets current user context.

Maps closely to setuser. The prototype of the function is as follows:

int setuser(char *username, char *password, int flags).

sys_siglist

System signal messages.

Change the code to use strsignal() instead.

sys_signame

System signal messages.

Change the code to use strsignal() instead.

UNIX bsd_signal Code Replacement

Code that uses the bsd_signal() function should be implemented using other signal functions in Interix.

The bsd_signal(sig, func) function call can be implemented as follows:

#include <signal.h>
void (*bsd_signal(int sig, void (*func)(int)))(int)
{
  struct sigaction act, oact;
  act.sa_handler = func;
  act.sa_flags = SA_RESTART;
  sigemptyset(&act.sa_mask);
  sigaddset(&act.sa_mask, sig);
  if (sigaction(sig, &act, &oact) == -1)
     return(SIG_ERR);
  return(oact.sa_handler);
}

This code can support calls to the bsd_signal function in a migrated application. You can also use the code to replace signal() in Berkeley Software Distribution (BSD)-derived applications as long as the signal handler expects a single parameter of the int type. If the handler expects any other parameters, signal() must be modified to use sigaction().

Additional Signal Functions

Interix provides the following POSIX functions for manipulating the signal set:

int sigemptyset(sigset_t * set);
int sigfillset(sigset_t * set);
int sigaddset(sigset_t * set, int signo);
int sigdelset(sigset_t * set, int signo);
int sigismember(const sigset_t * set, int signo);

The following example depicts the manipulation of the signal mask using sigpprocmask():

int sigprocmask(int how, sigset_t * set, sigset_t *oset);

You can determine whether a signal is pending by using the sigpending() function, as shown in the following example:

int sigpending(sigset_t * set);

Interprocess Communication

An operating system designed for multitasking or multiprocessing must provide mechanisms for communicating and sharing data between applications or interprocess communication (IPC). Some forms of IPC are designed for communication among processes running on the same computer, whereas other forms are designed for communicating across the network between different computers.

Pipes (Unnamed/Named, Half/Full Duplex)

Interix supports all the various forms of IPC. The following forms are most familiar to UNIX developers:

  • Anonymous pipes

  • Named pipes (FIFOs)

  • Shared memory

  • System V message queues

Anonymous Pipes

The primary use of pipes, which can be named or unnamed, is to communicate between related processes. They also have separate read and write file descriptors, which are created through a single function call. Process pipes are supported under Interix using the standard C run-time library. Interix supports all the pipe function calls, including popen, pclose, and pipe. There is no need to change any references to these calls in your code. Pipes are frequently used between UNIX processes to connect the standard output file descriptor of one process to the standard input file descriptor of a second process, causing the results of the first program to be treated as the input data for the second. This sequence of commands is called a pipeline.

You can use this mechanism to connect an Interix process to a Microsoft Win32® process that it creates. In nearly all cases, everything works without any change. Problems using pipes to communicate between Interix and Win32 processes generally fall into the following two categories:

  • Line termination character. Interix defines a line as ending with the \n character; Win32 defines a line as ending with the \r\n sequence. Some applications are sensitive to the precise line termination sequence. The flip command can be used in the pipe to change line termination as necessary.

  • End Of File (EOF) handling when attempting serial use of a pipe. After a Win32 process has closed a pipe to which it was writing, it is not possible for an Interix application to use that pipe serially. For example, this command will display only the contents of file1:

      (cmd.exe /c type file1; cat file2) | cat

    This problem can be solved by introducing a second pipeline using the cat32 tool:

      (cmd.exe /c type file1; cat file2 | cat32) | cat

With unnamed pipes, a parent process creates a pipe to communicate with its child process; the child process inherits and uses this pipe.

Named Pipes (FIFOs)

A named pipe, also referred to as first-in-first-out (FIFO), is a special type of pipe that is created in the file system but behaves like a process pipe. These are generally half-duplex pipes because they support only one-way communication. Full-duplex pipes are named pipes that allow two-way communication.

Interix supports the two function calls for creating a named pipe—mknod and mkfifo. If possible, it is better to use mkfifo to make FIFO special files because it is more portable. You do not need to modify code that uses these functions for compiling under Interix.

These named pipes are distinct from, and not interoperable with, the identically named Win32 interprocess communication mechanism, called Win32 named pipes. The only way to use Win32 named pipes to communicate between Interix and Win32 processes is through anonymous pipes, as desribed in the previous section.

There is a difference in the behavior of pipes in UNIX and Windows. UNIX uses the buffer concept to deal with programs that use pipes, whereas Windows uses the file system object. If the program has a tendency to acquire "back pressure," this difference becomes a major issue to contend with when migrating to Windows using Interix. This issue arises in sequences of programs connected by pipes when there is a finite capacity for the pipe in UNIX versus a Windows file system object that will almost never be exhausted (based on page-file size).

However, Interix exhibits the same behavior as UNIX because it adds a UNIX style buffer to the front end of the Windows pipe, which is a file system object. So change to the application is necessary, even if it relies on the presence of back pressure.

Shared Memory

Shared memory permits two or more processes to share a region of memory. Shared memory performance is considered the best of all interprocess communication (IPC) methods because data is not copied as part of the communication process. Instead, the same physical area of memory is accessed by both the client and the server.

Interix supports all of the System V IPC mechanisms. The shmat, shmctl, shmdt, and shmget mmap() routines can also be used to share memory between Interix and Win32 processes.

The command-line interfaces— ipcs and **ipcrm—**are also provided to manage shared memory segments. The ipcs interface reports the status of IPC objects. The ipcrm interface removes an IPC identifier, such as a shared memory segment.

Windows does not support the standard System V IPC mechanisms for shared memory (the shm*() APIs). It does, however, support memory-mapped files and memory-mapped page files, which you can use as an alternative to the shm*() APIs.

Note: Some of the lines in the following code have been displayed on multiple lines for better readability.

/* Consumer */
/* This program is a consumer. The shared memory
segment is created with a call to shmget, with the 
IPC_CREAT bit specified. */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "shm_com.h"
int main()
{
    void *shared_memory_loc = (void *)0;
    struct shared_struct *shared_stuff;
    int shmid;
    shmid = shmget((key_t)1111, sizeof
        (struct shared_struct), 0666 | IPC_CREAT);
    if (shmid == -1) 
    {
        fprintf(stderr, "shmget function failed\n");
        exit(EXIT_FAILURE);
    }
    /* Make the shared memory accessible to the program. */
    shared_memory_loc = shmat(shmid, (void *)0, 0);
    if (shared_memory_loc == (void *)-1) 
    {
        fprintf(stderr, "shmat function failed\n");
        exit(EXIT_FAILURE);
    }
    printf("Memory attached at %X\n", 
        (int)shared_memory_loc);
    /* Assign the shared_memory_loc segment to 
shared_stuff.
    Echo any text in "some_text".
    Continues until end is found in "some_input" 
        (1 in stored by     Producer).
    */
    shared_stuff = (struct shared_struct *)shared_memory_loc;
    shared_stuff->some_input = 0;
    while(1) 
    {
        if (shared_stuff->some_input) 
        {
            printf("You wrote: %s", shared_stuff->some_text);
            sleep(1); /* the Producer is waiting for this 
                                   process */
            shared_stuff->some_input = 0;
            if (strncmp(shared_stuff->some_text, 
                        "done", 4) == 0) 
            {
                break;
            }
        }
    }
    /* Detach and Delete shared memory */
    if (shmdt(shared_memory_loc) == -1) 
    {
        fprintf(stderr, "shmdt function failed\n");
        exit(EXIT_FAILURE);
    }
    if (shmctl(shmid, IPC_RMID, 0) == -1) 
    {
        fprintf(stderr, "shmctl(IPC_RMID) function failed\n");
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}
/* Producer */
/* This program is a producer of input text for the 
consumer. */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "shm_com.h"
int main()
{
    void *shared_memory_loc = (void *)0;
    struct shared_struct *shared_stuff;
    char buffer[BUFSIZ];
    int shmid;
    shmid = shmget((key_t)1111, sizeof(struct shared_struct), 
            0666 | IPC_CREAT);
    if (shmid == -1) 
    {
        fprintf(stderr, "shmget function failed\n");
        exit(EXIT_FAILURE);
    }
    shared_memory_loc = shmat(shmid, (void *)0, 0);
    if (shared_memory_loc == (void *)-1) 
    {
        fprintf(stderr, "shmat function failed\n");
        exit(EXIT_FAILURE);
    }
    printf("Memory attached at %X\n", 
        (int)shared_memory_loc);
    shared_stuff = (struct shared_struct *)shared_memory_loc;
    while(1) 
    {
        while(shared_stuff->some_input == 1) 
        {
            printf("waiting for Consumer...\n");
            sleep(1);
        }
        printf("Enter some text: ");
        fgets(buffer, BUFSIZ, stdin);
        strncpy(shared_stuff->some_text, buffer, TEXT_SZ);
        shared_stuff->some_input = 1;
        if (strncmp(buffer, "done", 4) == 0) 
        {
            break;
        }
    }
    if (shmdt(shared_memory_loc) == -1) 
    {
        fprintf(stderr, "shmdt function failed\n");
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}
/* A common header file to describe the memory being
shared. */
#define TEXT_SZ 256
struct shared_struct 
{
    int some_input;
    char some_text[TEXT_SZ];
};

System V Message Queues

Message queues are very similar to named pipes, but there is no need to open or close message queues. Interix supports all the message queue routines—msgctl, msgget, msgsnd, and msgrcv. Code that uses these functions does not need to be modified.

Note   Interix does not support Microsoft Message Queuing; however, similar functionality can be implemented using System V message queues.

Networking

The Interix SDK implementation uses the Windows network stack, through the use of Windows Sockets 2 (Winsock) to access the network. This means that TCP/IP sockets and all of the installed Winsock protocols are supported.

Note   Additional information about Winsock is available at
https://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/windows_sockets_start_page_2.asp.

This section covers the TCP/IP protocols and tools, and how remote procedure call (RPC) and sockets use TCP/IP.

TCP/IP Protocols and Tools

TCP/IP is an industry-standard suite of protocols designed for large Internet works spanning wide area network (WAN) links.

Windows Services for UNIX 3.5 provides two remote shell servers: the Windows-based Remote Shell service and the Interix rshd(1). If the Windows Remote Shell service is installed, it is enabled by default and the Interix rshd daemon is disabled by default in /etc/inetd.conf. The Windows and Interix versions of these servers should not be run at the same time because they will both try to access the same TCP/IP port, causing unpredictable results. To avoid problems, you should ensure that only the Windows or the Interix version of these servers is enabled at a time.

Remote Procedure Call

Open Network Computing (ONC) remote procedure call (RPC) is an IPC technique that allows client and server software to communicate with each other. These routines allow C programs to make procedure calls on other computers across the network. First, the client calls a procedure to send a data packet to the server. On receipt of the packet, the server calls a dispatch routine to perform the requested service and then sends back a reply. Finally, the procedure call returns to the client.

Interix provides rpc()–library routines for RPCs. The following must be present in the list of includes:

#include <rpc/rpc.h>

ONC RPC is different and is not compatible with Windows because this protocol uses Distributed Computing Environment (DCE) RPC for a number of system services. However, there are third-party software packages that implement ONC RPC on the Windows side. Tools such as Interix and NuTCRACKER provide support for ONC RPC. Additionally, shareware tools are available to support ONC RPC on Windows 2000.

Displaying Current TCP/IP Connections

Interix provides netstat, which shows protocol statistics and current TCP/IP network connections. It displays active TCP connections, ports on which the computer is receiving, Ethernet statistics, the Internet Protocol (IP) routing table, and IP statistics for the IP, Internet Control Message Protocol (ICMP), TCP, and User Datagram Protocol (UDP) protocols. Used without parameters, netstat displays active TCP connections.

Host Name to Address Translation

Interix does not support the generic transport name-to-address translation routines. It supports all the gethostby routines except the reentrant versions (routines with the _r suffix). While Interix does not ship with the *_r for the gethostby* family of APIs, you can freely install the BIND 9 library from the Interop /Tools site to gain the *_r functionality.

Table 5.3 lists other host name translation get or set routines that are not supported by Interix.

Table 5.3. Host-Name Translation Routines Not Supported by Interix

Function Name

Description

Suggested Interix Replacement

getdomainname

Gets the NIS domain name.

No equivalent in Interix. The principal Windows domain for the system can be obtained through getpdomain(). The prototype of the method is as follows:
int getpdomain (char * buf, int bufsize).

gethostid

Gets the unique identifier of the current host.

No equivalent in Interix, but should be a very rare occurrence in any application except a network administration application.

setdomainname

Sets the NIS domain name.

No equivalent in Interix.

sethostid

Sets the unique identifier of the current host.

No equivalent in Interix, but should never need to be set. It is restricted to the root user account.

sethostname

Sets the name of the host computer. (This call is restricted to the superuser and is normally used only when the system is booted.)

No equivalent in Interix.

Sockets

Interix implements BSD-style socket interfaces, including bind(), accept(), and connect(). This implementation uses the Windows network stack through the use of Winsock to access the network. This means that TCP/IP sockets and all of the installed Winsock protocols are supported.

The exceptions to socket support in Interix are discussed in the following sections:

  • Network Groups

  • Network Socket Calls

  • Transport Level Interface (XTI) Calls

  • Select Functionality

Network Groups

Interix does not support network group APIs. However, it supports network group designations in hosts.equiv and .rhosts files.

Network Socket Calls

These functions constitute the BSD sockets library. Interix provides all the network functions in the main C library, libc. For compatibility, Interix includes an empty libsocket.a library.

Table 5.4 lists the socket calls that are not supported by Interix.

Table 5.4. Socket Calls Not Supported by Interix

Function Name

Description

Suggested Interix Replacement

cmsg macros

Access ancillary data.

No equivalent in Interix.

freehostent

Removes IP node entry from linked list.

Currently no API support for IPv6.

getipnodebyaddr

Gets IP node entry.

Currently no API support for IPv6.

getipnodebyname

Gets IP node entry.

Currently no API support for IPv6.

inet_ntop

Processes network address structures.

Currently no API support for IPv6.

inet_pton

Creates a network address structure.

Currently no API support for IPv6.

rcmd_af

Returns a stream to a remote command and includes support for Ipv6.

Currently no API support for IPv6.

recvmsg

Receives a message from the socket.

No equivalent in Interix.

rexec_af

Returns a stream to a remote command and includes support for Ipv6.

Currently no API support for IPv6.

rresvport_af

Returns a descriptor to a socket with an address in the privileged port space.

Currently no API support for IPv6.

sendmsg

Sends a message to a socket.

No equivalent in Interix.

The recvmsg and sendmsg socket functions are used in many network applications but are not supported by Interix version 3.5 and earlier. These functions are the only way to pass an open file descriptor from one running process to another running process. These are mostly used for data exchange. On Windows Services for UNIX 3.5, recvfrom() and sendto() APIs can be used to exchange the data between the processes.

Each reentrant interface performs the same operation as its non–re-entrant counterpart does. The only difference is the _r suffix. The reentrant interfaces use buffers supplied by the caller to store returned results, and they are safe for use in both single-threaded and multithreaded applications. If the application is not multithreaded, then the _r routines can be safely replaced by removing the _r suffix and the additional parameters.

Note BIND 9 for *_r routines are available at https://www.interopsystems.com/tools.

Table 5.5 lists the reentrant routines and their Interix replacements.

Table 5.5. Interix Replacements for Reentrant Routines

Function Name

Description

Suggested Interix Replacement

getnetbyaddr_r

Searches for a network entry with the network address.

struct netent * getnetbyaddr (long net, int type)

getnetbyname_r

Searches for a network entry with specified name.

struct netent * getnetbyname (char *name)

getnetent_r

Enumerates network entries from the database.

struct netent * getnetent (void)

getprotobyname_r

Sequentially searches from the beginning of the file until a matching protocol name is found, or EOF is encountered.

struct protoent * getprotobyname(const char *name)

getprotobynumber_r

Sequentially searches from the beginning of the file until a matching protocol number is found, or EOF is encountered.

struct protoent * getprotobynumber (int proto)

getprotoent_r

Gets a matching protocol name.

struct protoent * getprotoent (void)

getservbyname_r

Returns a pointer to an object containing the information from a network services database.

struct servent *getservbyname (char *name, const char *proto)

getservbyport_r

Returns a pointer to an object containing the information from a network services database.

struct servent *getservbyport (int port, const char *proto)

getservent_r

Returns a pointer to an object containing the information from a network services database.

struct servent *getservent(void)

Transport Level Interface (XTI) Calls

The X/Open Transport Interface (XTI) APIs, defined by the  X/Open Transport Interface specification of Open Group, define protocol-independent networking functions similar to those provided by the old SVR4 TLI (Transport Layer Interface) APIs. Earlier, XTI and TLI were primarily used as interfaces to the ISO OSI protocol family or to the STREAMS networking stack. In general, XTI should be replaced by the more standard BSD sockets interface.

Interix support for XTI is limited to the functions and features required to access the UDP Internet protocol. Interix does not support some extended calls, which are mainly used with “expedited data” and the management or configuration of variables and parameters.

Table 5.6 lists the TLI calls that are not supported by Interix.

Table 5.6. Transport-Level Interface Calls Not Supported by Interix

Function Name

Description

Suggested Interix Replacement

nlsgetcall

Gets client data passed through the listener.

No equivalent in Interix.

nlsprovider

Gets the name of the transport provider.

No equivalent in Interix.

nlsrequest

Formats and sends a listener service request message.

No equivalent in Interix.

t_rcvv

Receives data or expedited data sent over a connection and puts the data into one or more noncontiguous buffers greater than or equal to.

No equivalent in Interix.

t_rcvvudata

Receives a data unit in one or more noncontiguous buffers.

No equivalent in Interix.

t_sndv

Sends data or expedited data from one or more noncontiguous buffers on a connection.

No equivalent in Interix.

t_sndvudata

Sends a data unit from one or more noncontiguous buffers.

No equivalent in Interix.

t_sysconf

Gets configurable XTI variables.

No equivalent in Interix.

Select Functionality

On UNIX select is limited to 512 FDs and 64 FDs on Windows by default.

You can fix this by defining FD_SETSIZE in winsock2.h or in the user-defined header file after including the winsock2.h header file:

#define FD_SETSIZE 512

On UNIX, select doesn't block on empty lists of fds. If you don't pass any socket fds, it blocks for the specified timeout. On the Interix environment, it returns immediately with an error.

Daemons and Services

A daemon in UNIX is a process that runs in the background to provide service to other applications and does not require a user interface. A service on Windows is the equivalent of a UNIX daemon. Normally, a daemon is started when the system is booted and runs without supervision until the system is shut down. Similarly, Windows services enable you to create long-running executable applications that run in their own Windows sessions. These services can be automatically started when the computer boots to continue across the logon sessions, can be paused and restarted, and do not show any user interface. Services are ideal for use on a server or for long-running functionality that does not interfere with other users who are working on the same computer. It is possible to run services in the security context of a specific user account that is different from the logged-on user or the default computer account.

This section provides an overview of the UNIX daemons and Windows services, explains their similarities and differences, and how to use them in the Interix environment.

Daemons

A UNIX daemon is a process that provides a specific service. The following are some examples:

  • The inetd daemon listens for connections on certain Internet sockets to start other daemons.

  • The nfsd daemon implements the user-level part of the NFS (directory/file sharing) services.

  • The syslogd daemon provides system tools with support for system and kernel logging.

On traditional UNIX systems, a daemon is a process that runs for an extended period of time, but it does not have a controlling terminal. A Windows service is a background process that is similar to a daemon process. You can run daemons directly on the Interix subsystem, or you can port daemons to run as Windows services.

Many daemons use setuid() or seteuid() to run as a particular user. However, this does not work on Windows because of the way in which Windows security is structured. A daemon invoked by inetd does not have these restrictions. It inherits the environment of the inetd process. In this context, the term daemon refers to a daemon process invoked by an Interix process that runs in the context of the Interix subsystem. An Interix service is an Interix process that is tied to the Win32 execution environment by the psxrun.exe program.

The chief advantage of running a daemon as a service is that the service runs as if it is logged on as a Windows user. This allows you to control the privileges and permissions granted to the service. When a daemon is logged on with a domain account, it enables the service to access the Windows network resources. However, unlike traditional UNIX daemons, Windows services cannot use mechanisms such as fork and exit to create a background process. This might make it difficult to port a daemon to run as a service.

Cron Service

Windows Services for UNIX provides the cron daemon that runs under the Interix subsystem. The cron daemon is used to execute scheduled commands. The cron daemon searches its spool directory (/var/spool/cron/tabs/) for crontab files that are named after fully qualified user names in the form domain+user and loads the crontab files it finds into memory. The cron daemon also searches for /etc/crontab that is in a different format. The cron daemon then wakes up every minute, examining all loaded crontab files and checking each command to see if it should be run in the current minute. The cron daemon requires the user to register a valid password before editing or running any crontab entry. The cron daemon uses this password to impersonate this user to execute any crontab entries submitted by this user. For cron to successfully execute another user's cron jobs, the user must have registered his or her password using crontab –p command. Without this password, cron cannot impersonate that user and will not execute the user's crontab commands.

A crontab file contains instructions to the cron daemon of the general form: run this command at this time on this date. Each user who has been assigned cron privileges has his or her own crontab file.

The Windows-based Cron service allows users to run commands at scheduled times, much like the UNIX cron daemon. Users run the crontab Windows command to schedule jobs.

To start and stop the Windows-based Cron service

  1. Go to Control Panel.

  2. Click Administrative Tools, and then Services.

  3. In the list of services, right-click Windows Cron Service.

  4. Click Properties. If the Startup type is disabled, select either Manual or Automatic.

  5. Click Apply.

  6. Click either Start or Stop.

Remote Shell Service

The Windows-based Remote Shell Service allows you to use a remote computer to execute commands on the computer running the Remote Shell Service, much like the UNIX rsh daemon.

The Windows Remote Shell Service (rshsvc.exe) is automatically installed on Windows Server-level products when you perform a standard installation of Windows Services for UNIX 3.5 and is automatically selected for a custom installation on these products.

rshsvc.exe resides in the %SFUDIR%\common directory.

To use the Windows Remote Shell Service

  1. Install the service from the Windows Services for UNIX 3.5 installation medium onto the target computer.

  2. Enable the service to start automatically or manually, as appropriate on your computer.

  3. Create a .rhosts file in the %windir%\system32\drivers\etc directory of the target system. The file must contain a list of computers and users who will be allowed to connect to the target system. Each line in this file should have the format as “hostname username”, same as UNIX host files. The members of the local users group must be able to read this file. However, this file is not writable. The typical inherited permissions in the default directory should be appropriate.

  4. Log on to the target system as the user who will connect to the system.

  5. Run rshpswd to store the password of the user.

  6. Connect from the originating system by using a simple command such as set to test the connectivity. For example, to connect to a system called example-srv, the command might read:

    rsh example-srv set

Note   Additional information on common configuration problems of the Remote Shell Service and their solutions is available at
https://www.microsoft.com/technet/interopmigration/unix/sfu/sfu35rsh.mspx.

The remote shell capability is inherently an insecure protocol. Use the Secure Shell (ssh) instead for a similar capability with greater security; this is available for both Windows and for the Interix subsystem.

Note You can download OpenSSH for Interix at https://www.interopsystems.com/tools/warehouse.htm.

The Interix Remote Shell Daemon

The Interix Remote Shell Daemon, rshd, runs as a daemon initiated by the inetd process and behaves in a more traditional UNIX manner. By default, rshd is disabled.

The Interix rshd uses a more traditional authentication mechanism, with both hosts.equiv and .rhosts supported. The format of each line in the hosts.equiv file used by Interix rshd should be as “hostname username”. Interix rshd supports a user-specific .rhosts file that is present in the home directory of the user. This file is checked only if a hosts.equiv match is not found. This file follows the same format as the hosts.equiv file.

As in traditional UNIX systems, the .rhosts file must reside in the home directory of the user. It must be a regular file owned by the user, and it must be writable only by the user. In addition, you should use only the Interix vi tool or other UNIX editor to create and edit the file. Windows editors can insert Windows text format line endings or other stray characters that will cause a failure. However, you can use the flip tool that converts text-file formats between POSIX and other formats like Microsoft MS-DOS®.

The following tools are supported:

  • regpwd

  • rcp

  • rlogin and rlogind

regpwd

The regpwd tool stores a copy of the password in a protected area accessible only by privileged processes. This password can then be used by privileged programs that impersonate the user, such as rshd, as well as the Windows Remote Shell Service (rshsvc).

rcp

The UNIX remote copy, rcp, is supported by the Interix rshd. This tool copies files between computers.

rlogin and rlogind

Interix also supports remote logins using the rlogin client and rlogind daemon. Remote logins do not require that a password be stored on the target computer. However, passwords are then passed in clear text over the network. On a traditional UNIX system, if all the necessary conditions are met, remote logins through rlogin do not require a password if .rhosts or hosts.equiv allows the remote user. Under Interix, if the default permissions and ownerships have not been changed and the SYSTEM account runs the Interix subsystem, then the behavior is as expected, except that regpwd must be used to store the password just as with rshd. In both traditional UNIX and Interix systems, if the remote logon cannot occur automatically, the remote user is prompted for the password of the target user. If the password is correctly provided, the user is logged on.

Keep the following in mind for the Interix rshd daemon:

  • The Interix rshd daemon does not provide a log of all failures and successes, as does Windows Remote Shell Service (rshsvc). However, when started with the –L option, it will write verbose success messages to the syslog. The syslogd is not enabled by default in Windows Services for UNIX 3.5, so you will need to enable it.

  • You must stop the Windows Remote Shell Service before you enable rshd.

  • DNS failures between the client and server systems may cause the computer names in .rhosts or hosts.equiv to not be resolved correctly. Hence, as a good practice, use IP addresses during initial testing and setup. After everything is working, revert to using DNS resolvable names to avoid later configuration issues if IP addresses change.

Note To enable the Interix Remote Shell Daemon, edit the file /etc/inetd.conf by using the Interix vi or other Interix or UNIX editor. Additional information on common configuration problems of the Interix Remote Shell Daemon and their resolutions is available at
https://www.microsoft.com/technet/interopmigration/unix/sfu/sfu35rsh.mspx.

Porting a Daemon to Interix

This section discusses porting a UNIX daemon to Interix and calling that daemon from either inetd or another master daemon. Daemons ported in this way cannot be run as a Windows service. If a daemon needs to run as a Windows service, use the instructions in the  “ Porting a Daemon to Interix Service” section.

When you port a daemon from UNIX to Interix, the daemon must have the following features:

  • The daemon call is an interface to allow a program to become a system daemon. This function causes the calling program to fork. The parent exits, and the child performs a setsid. This disassociates the process from its current process group, session, and controlling terminal. On successful completion of this call, the process is the session leader of a group in which it is the only member, and the session has no controlling terminal.

  • The signal-handling routine (terminate in this case) is a common characteristic of a daemon process.The daemon can perform cleanup operations when it receives the SIGTERM signal (for example, when the system shuts down) by using the signal handling routine. To use the terminate handling routine, the daemon must call the sigaction() system call, which installs its signal handler for the SIGTERM signal. Another signal, SIGHUP, is often used to signal to the daemon that it should reinitialize or restart.

Porting this daemon is a simple process. All you need to do is recompile, relink, and execute the daemon from the command line.

Porting a Daemon to Interix Service

The previous section discussed porting a UNIX daemon to Interix. However, an Interix daemon has some limitations. First, it can start other daemons, but individual daemons can be started through the init scripts that are part of startup of Interix only. Secondly, it is not integrated into the Windows service mechanisms. When a daemon is converted into a service, it can be managed in Windows from Control Panel (by clicking Administrative Tools, and then Services), as well as from the Interix command line.

Before going into more details on how to convert a daemon into a service, it is important to mention the following two commands that can help tie Interix processes to the Win32 execution environment:

  • The posix.exe program starts an Interix process with a controlling terminal.

  • The psxrun.exe program starts an Interix process without a controlling terminal.

In the case of a Windows service, the process must run without a controlling terminal. Run the psxrun program for such a case.

Note More details on posix and psxrun can be obtained from the Help manual of Windows Services for UNIX 3.5.

Interix services can be administered using Services in Control Panel or with the service tool provided with Interix.

The service tool is used to install the service as a particular user and to stop the service. The user name and password must be provided when the service is installed. If no user name is provided, the user name defaults to LocalSystem; this logs on the user as an administrator without access to the network. When a request to stop a particular service comes either from Services in Control Panel or from the service tool, psxrun sends the signal SIGTERM to the service.

Converting Daemon Code into Interix Service Code

To convert daemon code into Interix service code, the daemon code needs the following modifications:

  • Ensure that the service exits when it receives the SIGTERM signal. It must catch the SIGTERM signal, clean up, and shut down. Ideally, the service should not spend more than a few seconds in cleaning up; otherwise, the service can loose communications with the Services Control Manager.

  • Change the code so that it does not fork, and the parent exits.

    If the parent process exits, psxrun treats the program as having exited, and the Windows Service Control Manager reports that the service was never successfully started.

  • Do not call setsid( ) to create a new session. This does not work because of Windows Security. Use #ifdef to skip this code.

  • Do not access network drives through drive letters from the daemon. Network drives are typically mounted on drive letters when a user logs on and get unmounted when that user logs out. A service program cannot depend on a given network drive mounted on a given drive letter. If a service uses net.exe to mount a network drive, the drive letter it uses becomes unavailable to interactive users, which may cause Winlogon.exe to display error messages. If a service must access a network drive, reserve specific drive letters for exclusive use by the system. It is suggested that you use the /net file system.

Download

Get the UNIX Custom Application Migration Guide

Update Notifications

Sign up to learn about updates and new releases

Feedback

Send us your comments or suggestions