/***************************************************************************** * * * DH_NET.C * * * * Freely redistributable and modifiable. Use at your own risk. * * * * Copyright 1994 The Downhill Project * * * *****************************************************************************/ #if !defined(lint) && !defined(_NOIDENT) static const char* rcsid = "@(#)$RCSfile: dh_net.c,v $ $Revision: 1.1 $ (DOWNHILL) $Date: 2006/02/07 17:25:06 $"; #endif /* Include stuff *************************************************************/ #include "INCLUDE/DH.H" #include #include #include #include #include #include #include #include #include #include /* Define stuff **************************************************************/ #define DOWNHILL_RCMD_TIMEOUT 32 #define DOWNHILL_REXEC_TIMEOUT 16 /* Function stuff ************************************************************/ /* Report a host error ===================================================== */ #if (_DOWNHILL_POSIX_SOURCE == 0) void herror(char* error_Prefix) { /* Use perror(), 'cause there isn't an h_error */ perror(error_Prefix); } #endif /* Get user and password information from .netrc =========================== */ #if (_DOWNHILL_POSIX_SOURCE == 0) static char* downhill_Ruserpass_GetWord(FILE* file_Fs) { static char word_Text[1024]; int word_Position; static char line_Text[1024]; static int line_Position = 0; strcpy(word_Text,""); word_Position = 0; /* Loop to find a word */ do { /* Get a new line */ if (line_Text[line_Position] == '\0') { if (fgets(line_Text,sizeof(line_Text),file_Fs) == NULL) { return NULL; } line_Position = 0; } /* Skip any white space */ while ((line_Text[line_Position] == ' ') || (line_Text[line_Position] == '\t') || (line_Text[line_Position] == '\n')) { line_Position++; } /* Get the word */ while ((line_Text[line_Position] != ' ') && (line_Text[line_Position] != '\t') && (line_Text[line_Position] != '\n') && (line_Text[line_Position] != '\0')) { word_Text[word_Position] = line_Text[line_Position]; word_Text[word_Position+1] = '\0'; word_Position++; line_Position++; } } while (!strcmp(word_Text,"")); /* Return what we got */ return word_Text; } void ruserpass(char* host_Name,char** user_Name,char** user_Password) { FILE* file_Fs; char netrc_File[MAXPATHLEN+1]; char* netrc_Word; static char netrc_Name[32]; static char netrc_Password[32]; int machine_Match = 0; int machine_Matched = 0; /* Open the file */ strcpy(netrc_File,Downhill_User_Dir); strcat(netrc_File,"\\"); strcat(netrc_File,_DOWNHILL_NETRC_FILE); file_Fs = fopen(netrc_File,"rt"); if (file_Fs == NULL) { return; } /* Loop through the file */ do { netrc_Word = downhill_Ruserpass_GetWord(file_Fs); if (netrc_Word == NULL) { break; } else if (!strcasecmp(netrc_Word,"machine")) { netrc_Word = downhill_Ruserpass_GetWord(file_Fs); if (netrc_Word != NULL) { machine_Match = (!strcasecmp(netrc_Word, host_Name)); if (machine_Match) { machine_Matched = 1; } } } else if (!strcasecmp(netrc_Word,"default")) { if (!machine_Matched) { machine_Match = 1; } else { machine_Match = 0; } } else if (!strcasecmp(netrc_Word,"login")) { netrc_Word = downhill_Ruserpass_GetWord(file_Fs); if ((netrc_Word != NULL) && (machine_Match)) { strcpy(netrc_Name,netrc_Word); *user_Name = netrc_Name; } } else if (!strcasecmp(netrc_Word,"password")) { netrc_Word = downhill_Ruserpass_GetWord(file_Fs); if ((netrc_Word != NULL) && (machine_Match)) { strcpy(netrc_Password,netrc_Word); *user_Password = netrc_Password; } } } while (netrc_Word != NULL); return; } #endif /* Execute a password-protected remote command ============================= */ /* This is based on the BSD rexec. */ #if (_DOWNHILL_POSIX_SOURCE == 0) int rexec(char** server_Host,unsigned short server_Port,char* server_User, char* server_Password,char* server_Command,int* client_Stderr) { struct hostent* server_Info; struct sockaddr_in client_AddrStdout; int client_Stdout; struct sockaddr_in client_AddrStderr; unsigned short client_PortStderr = 0; int sec_Count = 0; char result_Character; /* Normalize the host */ server_Info = gethostbyname(*server_Host); if (server_Info == NULL) { herror(*server_Host); return -1; } *server_Host = server_Info->h_name; /* Get any additional information */ ruserpass(server_Info->h_name,&server_User,&server_Password); retry: /* Open stdout ----------------------------------------------------- */ client_Stdout = socket(AF_INET,SOCK_STREAM,0); if (client_Stdout < 0) { perror("rexec: socket"); return -1; } client_AddrStdout.sin_family = server_Info->h_addrtype; client_AddrStdout.sin_port = htons(server_Port); memcpy((caddr_t)(&client_AddrStdout.sin_addr),server_Info->h_addr, server_Info->h_length); if (connect(client_Stdout,(struct sockaddr*)(&client_AddrStdout), sizeof(client_AddrStdout)) < 0) { /* Close the socket */ closesocket(client_Stdout); /* Should we retry? */ if ((errno == ECONNREFUSED) && (sec_Count <= DOWNHILL_REXEC_TIMEOUT)) { /* Wait a bit */ sleep(sec_Count); sec_Count *= 2; goto retry; } /* Couldn't get the connection */ perror(server_Info->h_name); return -1; } /* Open stderr ----------------------------------------------------- */ if (client_Stderr == NULL) { send(client_Stdout,"\0",1,0); client_PortStderr = 0; } else { struct sockaddr_in temp_Addr; int temp_AddrSize; char temp_Port[8]; int temp_Socket; int temp_Socket2; temp_Socket = socket(AF_INET,SOCK_STREAM,0); if (temp_Socket < 0) { goto bad; } listen(temp_Socket,1); temp_AddrSize = sizeof(client_AddrStderr); if ((getsockname(temp_Socket, (struct sockaddr*)(&client_AddrStderr),&temp_AddrSize) < 0) || (temp_AddrSize != sizeof(client_AddrStderr))) { perror("getsockname"); closesocket(temp_Socket); goto bad; } client_PortStderr = ntohs((unsigned short)client_AddrStderr.sin_port); sprintf(temp_Port,"%u",client_PortStderr); write(client_Stdout,temp_Port,(int)strlen(temp_Port)+1); temp_AddrSize = sizeof(temp_Addr); temp_Socket2 = accept(temp_Socket, (struct sockaddr*)(&temp_Addr),&temp_AddrSize); closesocket(temp_Socket); if (temp_Socket2 < 0) { perror("accept"); client_PortStderr = 0; goto bad; } *client_Stderr = temp_Socket2; } /* Send the command ------------------------------------------------ */ send(client_Stdout,server_User,(int)strlen(server_User)+1,0); send(client_Stdout,server_Password,(int)strlen(server_Password)+1,0); send(client_Stdout,server_Command,(int)strlen(server_Command)+1,0); /* Handle result --------------------------------------------------- */ if (recv(client_Stdout,&result_Character,1,0) != 1) { perror(*server_Host); goto bad; } if (result_Character != 0) { /* Read the fail message */ while (recv(client_Stdout,&result_Character,1,0) == 1) { write(fileno(stderr),&result_Character,1); if (result_Character == '\n') { break; } } goto bad; } return client_Stdout; bad: if (client_PortStderr) { closesocket(*client_Stderr); } closesocket(client_Stdout); return -1; } #endif /* Open a socket to a reserved port ======================================== */ #if (_DOWNHILL_POSIX_SOURCE == 0) int rresvport(unsigned short* client_Port) { int client_Sd; struct sockaddr_in client_Addr; /* Loop 'til we get something */ (*client_Port)++; for (;;) { (*client_Port)--; if (*client_Port < 0) { errno = EAGAIN; return -1; } /* Open the socket */ client_Sd = socket(PF_INET,SOCK_STREAM,0); if (client_Sd == -1) { return -1; } /* Bind to the port */ client_Addr.sin_family = AF_INET; client_Addr.sin_port = htons(*client_Port); client_Addr.sin_addr.s_addr = INADDR_ANY; if (bind(client_Sd,(struct sockaddr*)(&client_Addr), sizeof(client_Addr)) == -1) { int error_Number = GetLastError(); /* Close the socket */ closesocket(client_Sd); /* Try again */ if (error_Number == EADDRINUSE) { continue; } return -1; } break; } /* Return the socket */ return client_Sd; } #endif /* Execute a remote command ================================================ */ /* This is based on the BSD rcmd. */ #if (_DOWNHILL_POSIX_SOURCE == 0) int rcmd(char** server_Host,unsigned short server_Port,char* client_User, char* server_User,char* server_Command,int* client_Stderr) { int client_Stdout; unsigned short client_Port = IPPORT_RESERVED-1; struct sockaddr_in client_AddrStdout; struct sockaddr_in client_AddrStderr; struct hostent* server_Info; int sec_Count = 1; fd_set sock_Set; char result_Character; int error_Number; /* The the info on the server */ server_Info = gethostbyname(*server_Host); if (server_Info == NULL) { return -1; } *server_Host = server_Info->h_name; /* Find a socket --------------------------------------------------- */ for (;;) { client_Stdout = rresvport(&client_Port); if (client_Stdout == -1) { if (errno == EAGAIN) { fprintf(stderr,"socket: All ports in use\n"); } else { perror("rcmd: socket"); } return -1; } /* Set up the socket */ client_AddrStdout.sin_family = server_Info->h_addrtype; memcpy((caddr_t)(&client_AddrStdout.sin_addr), server_Info->h_addr_list[0],server_Info->h_length); client_AddrStdout.sin_port = htons(server_Port); /* Connect */ if (connect(client_Stdout, (struct sockaddr*)(&client_AddrStdout), sizeof(client_AddrStdout)) >= 0) { /* Connect worked */ break; } error_Number = GetLastError(); /* Connect failed */ closesocket(client_Stdout); /* Refused? */ if ((error_Number == ECONNREFUSED) && (sec_Count <= DOWNHILL_RCMD_TIMEOUT)) { /* Wait a bit and try again */ sleep(sec_Count); sec_Count *= 2; continue; } /* If there's other addresses, try 'em */ if (server_Info->h_addr_list[1] != NULL) { int errno_Old = errno; fprintf(stderr,"connect to address %s: ", inet_ntoa(client_AddrStdout.sin_addr)); errno = errno_Old; perror(NULL); server_Info->h_addr_list++; memcpy((caddr_t)(&client_AddrStdout.sin_addr), server_Info->h_addr_list[0],server_Info->h_length); fprintf(stderr,"Trying %s...\n", inet_ntoa(client_AddrStdout.sin_addr)); continue; } /* Couldn't find any */ perror(server_Info->h_name); return -1; } /* Open stderr ----------------------------------------------------- */ if (client_Stderr == NULL) { send(client_Stdout,"",1,0); client_Port = 0; } else { /* Create the stderr socket */ char sock_Port[8]; int sock_Temp; int client_Stderr2; int len; client_Port--; sock_Temp = rresvport(&client_Port); if (sock_Temp == -1) { goto bad; } if (listen(sock_Temp,1) == -1) { goto bad; } /* Tell the host were the stderr port is */ sprintf(sock_Port,"%d",client_Port); if (send(client_Stdout,sock_Port,(int)strlen(sock_Port)+1,0) != (int)strlen(sock_Port)+1) { perror("send: setting up stderr"); closesocket(sock_Temp); goto bad; } FD_ZERO(&sock_Set); FD_SET(client_Stdout,&sock_Set); FD_SET(sock_Temp,&sock_Set); errno = 0; if ((select(FD_SETSIZE,&sock_Set,(fd_set *)NULL,(fd_set *)NULL, (struct timeval *)NULL) < 1) || (!FD_ISSET(sock_Temp,&sock_Set))) { if (errno != 0) { perror("select: setting up stderr"); } else { fprintf(stderr, "select: protocol failure in setup.\n"); } closesocket(sock_Temp); goto bad; } /* Wait for the host to connect */ len = sizeof(client_AddrStderr); client_Stderr2 = accept(sock_Temp, (struct sockaddr*)&client_AddrStderr,&len); closesocket(sock_Temp); if (client_Stderr2 == -1) { perror("accept"); client_Port = 0; goto bad; } *client_Stderr = client_Stderr2; /* Make sure we connected right */ client_AddrStderr.sin_port = ntohs(client_AddrStderr.sin_port); if ((client_AddrStderr.sin_family != AF_INET) || (client_AddrStderr.sin_port >= IPPORT_RESERVED) || (client_AddrStderr.sin_port < IPPORT_RESERVED/2)) { fprintf(stderr, "socket: protocol failure in circuit setup.\n"); goto bad2; } } /* Send the command ------------------------------------------------ */ send(client_Stdout,client_User,(int)strlen(client_User)+1,0); send(client_Stdout,server_User,(int)strlen(server_User)+1,0); send(client_Stdout,server_Command,(int)strlen(server_Command)+1,0); /* Handle the result ----------------------------------------------- */ if (recv(client_Stdout,&result_Character,1,0) != 1) { perror(*server_Host); goto bad2; } if (result_Character != 0) { /* The command failed, read the result */ while (recv(client_Stdout,&result_Character,1,0) == 1) { write(fileno(stderr),&result_Character,1); if (result_Character == '\n') { break; } } goto bad2; } return client_Stdout; bad2: if (client_Port) { closesocket(*client_Stderr); } bad: closesocket(client_Stdout); return -1; } #endif /* Check to see if the hostnames match ===================================== */ static int downhill_Ruserok_CheckHost(char* hostname_Client, char* hostname_Candidate) { char hostname_CandidateFull[MAXHOSTNAMELEN+1]; /* Build the name */ strcpy(hostname_CandidateFull,hostname_Candidate); /* Does the candidate end in a "."? */ if (hostname_CandidateFull[strlen(hostname_CandidateFull)-1] == '.') { char hostname_Local[MAXHOSTNAMELEN+1]; #ifndef NEED_NODENAME /* Get the local domain */ if (gethostname(hostname_Local,MAXHOSTNAMELEN) == 0) { #endif char* domain_Local = strchr(hostname_Local,'.'); /* If there's a domain, use it */ if (domain_Local != NULL) { strcat(hostname_CandidateFull,domain_Local); } #ifndef NEED_NODENAME } #endif } /* Disallowed? */ if ((hostname_Candidate[0] == '-') && (!strcasecmp(hostname_Client,&(hostname_CandidateFull[1])))) { return FALSE; } /* Allowed? */ if ((!strcmp("+",hostname_CandidateFull)) || (!strcasecmp(hostname_Client,hostname_CandidateFull))) { return TRUE; } /* Couldn't find */ return FALSE; } /* Check if host and user are valid ======================================== */ static int downhill_Ruserok_CheckHostUser(FILE* file_Fs,char* hostname_Client, char* username_Server,char* username_Client) { char line_Text[MAXHOSTNAMELEN+1]; unsigned int line_Index = 0; char hostname_Candidate[MAXHOSTNAMELEN+1]; unsigned int hostname_Index = 0; char username_Candidate[MAXHOSTNAMELEN+1]; unsigned int username_Index; /* Loop through all the hostnames in the file */ while (fgets(line_Text,sizeof(line_Text),file_Fs)) { /* Clear out the candidates */ strcpy(hostname_Candidate,""); hostname_Index = 0; /* Clear out any leading white-space */ line_Index = 0; while ((line_Text[line_Index] == ' ') || (line_Text[line_Index] == '\t')) { line_Index++; } /* Get the host name */ while ((line_Text[line_Index] != '\n') && (line_Text[line_Index] != '\t') && (line_Text[line_Index] != ' ') && (line_Text[line_Index] != '\0')) { hostname_Candidate[hostname_Index] = line_Text[line_Index]; line_Index++; hostname_Index++; } hostname_Candidate[hostname_Index] = '\0'; /* Do the host names match? */ if (downhill_Ruserok_CheckHost(hostname_Client, hostname_Candidate)) { /* Is there a user name? */ while ((line_Text[line_Index] == ' ') || (line_Text[line_Index] == '\t')) { line_Index++; } if ((line_Text[line_Index] == '\n') || (line_Text[line_Index] == '\0')) { /* If the client user is the same as the server user, they we're OK */ if (!strcasecmp(username_Client, username_Server)) { return TRUE; } } else { /* Loop through all the users */ while ((line_Text[line_Index] != '\n') && (line_Text[line_Index] != '\0')) { /* Clear any white space */ while ((line_Text[line_Index] == ' ') || (line_Text[line_Index] == '\t')) { line_Index++; } if ((line_Text[line_Index] == '\n') || (line_Text[line_Index] == '\0')) { break; } /* Clear out the candidate */ username_Index = 0; /* Get the user name */ while ((line_Text[line_Index] != '\n') && (line_Text[line_Index] != '\t') && (line_Text[line_Index] != ' ') && (line_Text[line_Index] != '\0')) { username_Candidate[ username_Index] = line_Text[ line_Index]; line_Index++; username_Index++; } username_Candidate[username_Index] = '\0'; /* Are we explicitly excluded? */ if ((username_Candidate[0] == '-') && (!strcasecmp(username_Client, &(username_Candidate[1])))) { return FALSE; } /* Do we allowed? */ if ((!strcmp("+",username_Candidate)) || (!strcasecmp(username_Client, username_Candidate))) { return TRUE; } } } } } return FALSE; } /* Check if a remote user can execute commands on this server ============== */ #if (_DOWNHILL_POSIX_SOURCE == 0) int ruserok(char* hostname_Client,int root_Want,char* user_Client, char* user_Server) { FILE* file_Fs; char rhosts_File[MAXPATHLEN+1]; /* If they don't want to be root, open up the "hosts.equiv" file */ file_Fs = root_Want?(FILE*)NULL:fopen(_DOWNHILL_HOSTSEQUIV_PATH,"rt"); /* If the "hosts.equiv" file opened up, check it */ if (file_Fs != NULL) { if (downhill_Ruserok_CheckHostUser(file_Fs,hostname_Client, user_Server,user_Client)) { fclose(file_Fs); return 0; } fclose(file_Fs); } /* Try the .rhosts file */ strcpy(rhosts_File,Downhill_User_Dir); strcat(rhosts_File,"\\"); strcat(rhosts_File,_DOWNHILL_RHOSTS_FILE); file_Fs = fopen(rhosts_File,"rt"); /* If it opened up, check it */ if (file_Fs != NULL) { if (downhill_Ruserok_CheckHostUser(file_Fs,hostname_Client, user_Server,user_Client)) { fclose(file_Fs); return 0; } fclose(file_Fs); } /* Not allowed */ return -1; } #endif