2

I'm getting the following compiler warning each time I try and compile an application I'm building:

└─$ gcc -o svr2 common.h launch.c tools.c netops.c
netops.c: In function ‘acceptClient’:
netops.c:138:33: warning: implicit declaration of function ‘displayMenu’ [-Wimplicit-function-declaration]
  138 |                                 displayMenu(clnFd);
      |                                 ^~~~~~~~~~~

The application consists of 4 files:

  • Common.h - function prototypes and defines
  • Launch.c - main entry point
  • Netops.c - Networking functions
  • Tools.c - Tools that the server will provide

All .c files have #include "common.h" as their first line. Can someone please have a look and see why it thinks I'm implicitly declaring this function? (If there is any vulnerable code ignore it as this is going to be a CTF binary).

Code base as follows (most code left out for brevity or is incomplete at present):

common.h

#ifndef _COMMON_H_
#define _COMMON_H_

/* System includes here */

/* List of defines here */

/* Function prototypes */
int launchServer();
int acceptClient(int);
int writeToClient(int, char *);
int readFromClient(int, char *);
int b64Encoder(int);
int checkPassword(int);
int printFlag();
int b64Decode(int);
void displayMenu(int);

#endif /* _COMMON_H_ */

netops.c

#include "common.h"

// Some code omitted here
//...
int acceptClient(int svrFd)
{
    struct sockaddr_in cln;
    int result = 0;
    int clnFd = 0;
    int clnPort = 0;
    int pid = 0;
    socklen_t len = 0;
    char *clnIp;

    // Attempt to accept incoming client
    len = sizeof(cln);
    for(;;)
    {
        clnFd = accept(svrFd, (struct sockaddr *)&cln, &len);
        if(SOCKERR == clnFd)
        {
            fprintf(stderr, "[-] Unable to accept incoming client. Error is: %s (%d).\n", strerror(errno), errno);
            close(clnFd);
            continue;
        }

        clnIp = inet_ntoa(cln.sin_addr);
        clnPort = ntohs(cln.sin_port);

        fprintf(stdout, "[*] New connection from client: %s:%d.\n", clnIp, clnPort);

        // Set client socket to non-blocking
        result = fcntl(clnFd, F_SETFL, fcntl(clnFd, F_GETFL) | O_NONBLOCK);
        if(FCNTLERR == result)
        {
            fprintf(stderr, "[-] Unable to set the client port to non-blocking. Attempting to continue. Error is: %s (%d).\n", strerror(errno), errno);
        }

        pid = fork();
        if(pid < 0)
        {
            // Unable to fork
            fprintf(stderr, "[-] Unable to fork new process for %s:%d. Error is: %s (%d).\n", clnIp, clnPort, strerror(errno), errno);
            close(clnFd);
            continue;
        }

        if(pid == 0)
        {
            // This is the client process
            fprintf(stdout, "[*] Forked new process for client: %s:%d.\n", clnIp, clnPort);
            result = checkPassword(clnFd);
            if(CLNERR == result)
            {
                close(clnFd);
                return CLNERR;
            }
            if(CLNCLOSE == result)
            {
                fprintf(stderr, "[-] Client connection %s:%d closed.\n", clnIp, clnPort);
                close(clnFd);
                continue;
            }
            if(PASSCOUNTEXCEED == result)
            {
                fprintf(stderr, "[-] Client %s:%d exceeded the maximum password attempts allowed.\n", clnIp, clnPort);
                close(clnFd);
                continue;
            }
            if(SUCCESS == result)
            {
                // FUNCTION CALLED HERE
                displayMenu(clnFd);
            }
        }
    }

    // Should never hit here. If it does, it means we have broken out of the while loop for an unknown reason.
    close(clnFd);
    return CLNERR;
}
//...
// Some code omitted here

tools.c

#include "common.h"


int b64Encode(int clnFd)
{
    //...
    return SUCCESS;
}

int b64Decode(int clnFd)
{
    return 0;
}

void displayMenu(int clnFd)
{
    // FUNCTION CODE HERE
    int result = SUCCESS;
    result = b64Encode(clnFd);

}

int checkPassword(int clnFd)
{
    int passCount = 0;
    int clnWr = SUCCESS;
    int clnRd = SUCCESS;
    int result = SUCCESS;
    ssize_t len = 0;
    char *readBuff;
    char *writeBuff;
    char *writeText;
    const char *correctPwd = "************";

    // Malloc 1024 bytes to both read and write buffers
    readBuff = (char *)malloc(R_BUFLEN * sizeof(char));
    writeBuff = (char *)malloc(W_BUFLEN * sizeof(char));

    // Request the password
    writeText = "Enter the server password to continue";
    snprintf(writeBuff, W_BUFLEN, "%s (Attempt %d of %d): ", writeText, passCount+1, MAXPASSCOUNT);
    clnWr = writeToClient(clnFd, writeBuff);
    memset(writeBuff, ZEROBUF, (W_BUFLEN * sizeof(*writeBuff)));
    if(SUCCESS != clnWr)
    {
        free(readBuff);
        free(writeBuff);
        return CLNERR;
    }

    // Read incoming password
    for(;;)
    {
        clnRd = readFromClient(clnFd, readBuff);
        if(READERR == clnRd)
        {
            free(readBuff);
            free(writeBuff);
            return CLNERR;
        }

        if(CLNCLOSE == clnRd)
        {
            free(readBuff);
            free(writeBuff);
            return CLNCLOSE;
        }
        if(SUCCESS == clnRd)
        {
            if(strncmp(correctPwd, readBuff, PASSLEN) == MATCH)
            {
                writeText = "Correct password supplied! Welcome to the server.\n";
                snprintf(writeBuff, W_BUFLEN, "%s", writeText);
                clnWr = writeToClient(clnFd, writeBuff);
                memset(writeBuff, ZEROBUF, (W_BUFLEN * sizeof(*writeBuff)));
                if(SUCCESS != clnWr)
                {
                    free(readBuff);
                    free(writeBuff);
                    return CLNERR;
                }
                free(readBuff);
                free(writeBuff);
                return SUCCESS;
            }
            else
            {
                passCount++;
                if(MAXPASSCOUNT == passCount)
                {
                    writeText = "Maximum attempts reached. Goodbye!\n";
                    snprintf(writeBuff, W_BUFLEN, "%s", writeText);
                    clnWr = writeToClient(clnFd, writeBuff);
                    memset(writeBuff, ZEROBUF, (W_BUFLEN * sizeof(*writeBuff)));
                    if(SUCCESS != clnWr)
                    {
                        free(readBuff);
                        free(writeBuff);
                        return CLNERR;
                    }
                    return PASSCOUNTEXCEED;
                }
                else
                {
                    writeText = "Incorrect password supplied.\nEnter the server password to continue";
                    snprintf(writeBuff, W_BUFLEN, "%s (Attempt %d of %d): ", writeText, passCount+1, MAXPASSCOUNT);
                    clnWr = writeToClient(clnFd, writeBuff);
                    memset(writeBuff, ZEROBUF, (W_BUFLEN * sizeof(*writeBuff)));
                    if(SUCCESS != clnWr)
                    {
                        free(readBuff);
                        free(writeBuff);
                        return CLNERR;
                    }
                }
            }
        }
    }

    // Should never hit here. If it does, it means an unknown error has occurred.
    free(readBuff);
    free(writeBuff);
    return CLNERR;
}

launch.c

#include "common.h"


int main(int argc, char *argv[])
{
    int svrFd = 0;
    int clnFd = 0;

    // Start the server
    svrFd = launchServer();
    if(SVRERR == svrFd)
    {
        fprintf(stderr, "[-] Fatal server error. Exiting.");
        return GENERR;
    }

    // Accept incoming clients
    clnFd = acceptClient(svrFd);
    if(CLNERR == clnFd)
    {
        fprintf(stderr, "[-] Fatal client error. Exiting.");
        return GENERR;
    }

    return 0;
}

tyrone 1988
  • 321
  • 2
  • 11
  • I don't think it is causing your issue, but do not compile `common.h` explicitly. It is a header, and compiling a proper header is at best useless. – John Bollinger Mar 05 '23 at 21:57
  • 1
    Please make a more [mre]. There is too much unrelated code and some code is not shown. If you try to find the smallest code which still has the same probem you are probably 95% at the solution. – Yunnosch Mar 05 '23 at 22:04
  • 2
    `_COMMON_H_` is a [reserved identifier](https://port70.net/~nsz/c/c11/n1570.html#7.1.3), and using it invokes undefined behavior. There's a chance you're running into a name collision and your header isn't getting fully included, or some other problem. If you change it to a non-reserved identifier and still have the problem, there's a chance you have a stray non-printing character somewhere in your code. – Andrew Henle Mar 05 '23 at 22:15
  • @AndrewHenle aah never knew that, changed and it's now fixed thank you – tyrone 1988 Mar 05 '23 at 22:21
  • 1
    Note that you should not, in general, create function, variable, tag or macro names that start with an underscore. Part of [C11 §7.1.3 Reserved identifiers](https://port70.net/~nsz/c/c11/n1570.html#7.1.3) says: — _All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use._ — _All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces._ See also [What does double underscore (`__const`) mean in C?](https://stackoverflow.com/q/1449181) – Jonathan Leffler Mar 06 '23 at 04:11

1 Answers1

3

Thank you @AndrewHenle for pointing out _COMMON_H_ being a reserved identifier, changing that fixed it.

_COMMON_H_ is a reserved identifier, and using it invokes undefined behavior. There's a chance you're running into a name collision and your header isn't getting fully included, or some other problem. If you change it to a non-reserved identifier and still have the problem, there's a chance you have a stray non-printing character somewhere in your code.

James Risner
  • 5,451
  • 11
  • 25
  • 47
tyrone 1988
  • 321
  • 2
  • 11