Read file descriptor 3 in C

Are there still any C programmers alive out there? I have an odd puzzle. I am trying to customize a program called passwordcheck.c ( For some crazy reason, it expects input on file descriptor 3. I have the following C code:

    char        buffer[600];
    int         cnt;

    cnt = read(3, buffer, sizeof(buffer));
    printf("%d: %s\n", buffer);
    fprintf(stderr, "ERROR %s\n", strerror(errno));

the 'read' is pretty much the same as the original version. This program compiles OK. The problem is how to pass something on fd 3?!

there are no test examples for the C version, but some comments in a python version show testing with the command line:

printf "%s\0%s\0%s\0" unknown bloggs Y123456 | ./ id 3<&0

So, I've tried:

echo pete | ./checkpassword 3<&0

but that gives a segmentation fault.

I've tried:

> echo pete >&3 | ./checkpassword
-bash: 3: Bad file descriptor
Segmentation fault

Any ideas on how to send something to fd 3 so I can test this program?
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Kent OlsenDBACommented:
Hi Mark,

The first three streams are STDIN, STDOUT, and STDERR.  Based on your description, the program is probably trying to read messages that were written to STDERR.

Kent OlsenDBACommented:
Hi Mark,

Have you seen the site's page with test instructions?
Become a Microsoft Certified Solutions Expert

This course teaches how to install and configure Windows Server 2012 R2.  It is the first step on your path to becoming a Microsoft Certified Solutions Expert (MCSE).

evilrixSenior Software Engineer (Avast)Commented:
>>  it expects input on file descriptor 3
The standard file descriptors (as already covered by Kdo and ozo) are 0 to 2.

3 to 9 are user definable, so you are probably expected to create one on a file using the open function.
MarkAuthor Commented:
Have you seen the site's page with test instructions?
Yes, that's where I was looking at the original checkpassword.c, but I'll look again for more instructions. Maybe I missed them. The beginning of the program is:

    33    if (!argv[1]) _exit(2);
    35    uplen = 0;
    36    for (;;) {
    37      do
    38        r = read(3,up + uplen,sizeof(up) - uplen);
    39      while ((r == -1) && (errno == error_intr));
    40      if (r == -1) _exit(111);
    41      if (r == 0) break;
    42      uplen += r;
    43      if (uplen >= sizeof(up)) _exit(1);
    44    }
    45    close(3);

They begin right-off reading 3, which is basically the same as I'm doing.

>>  it expects input on file descriptor 3  The standard file descriptors (as already covered by Kdo and ozo) are 0 to 2.
yes, that I already know.
3 to 9 are user definable, so you are probably expected to create one on a file using the open function.
Right, so if you see the code fragment I posted immediately above, the original C program is simply reading 3. What I'm trying to figure out is a way to send something to 3. Shell script? another program?

At the shell level, it's easy to send to 1 or 2: echo "something" >&2, but using 3 gives me a "Bad file descriptor" error. This odd mechanism makes it tough to test!

How do I send something on fd 3 to a C program?
MarkAuthor Commented:
More info ...

The website page kdo referred to is They show testing with qmail as:

Simulate a failed POP login:
     # /var/qmail/bin/qmail-popup blah /bin/checkpassword pwd
     +OK <...@blah>
     user Frodo
     pass Friend
     -ERR authorization failed

It appears that qmail-popup takes the checkpassword program path as an argument. This impiles to me that it possibly opens the fd 3, then runs the checkpassword program from within qmail-popup ... as a child?

I could try that. I'll create another program: ckpw.c, to open fd 3, write something to it, then launch/spawn my checkpassword program.

Suggestions on this idea? I don't even know how to open a file descriptor in C. I'll research, but if someone can just tell me right-off it would save some time.
Kent OlsenDBACommented:
Hi Mark,

File descriptors are usually assigned in order.  0, 1, and 2 are reserved.  3 would be the first file descriptor opened by the program.  The descriptor is just a number is simply an index into a table (owned by the process) that then indexes into the system table.

The descriptor can refer to any file or file type in the system.  What I would expect in this case is that the first program opens a pipe that is to be read by your password program.  It's the first thing that the program opens so its descriptor is 3.
evilrixSenior Software Engineer (Avast)Commented:
What I am saying is the example code is incomplete. It is just showing you how to do things, but it is up to you to open the file descriptor unless you wish to read from stdin.

You can't redirect things to a file descriptor called 3 because it is not a standard file descriptor. It doesn't exist, except within the scope of your process if you open it or any other process that inherits it from your process.

>> This impiles to me that it possibly opens the fd 3, then runs the checkpassword program from within qmail-popup ... as a child?

Bingo :)
evilrixSenior Software Engineer (Avast)Commented:
Sorry Kent, it seems we crossed streams with more or less the same info.
MarkAuthor Commented:
By Jove, I think I've got it! I created the program ckpw.c as shown below. I used pipe() which creates an fd array with fd[0] for input and fd[1] for output (apparently). The output of my ckpw program shows fd[0] =3, and fd[1] = 4. I used execve() to launch the checkpassword program.

I don't really know how my real invoker (Dovecot) launches checkpassword, but this should give me  a start.

Test Results:

$ ckpw
fd[0] (read): 3, fd[1] (write) 4
entered checkpassword
finished reading
15: Hello, world!

ERROR Success
/* ckpw.c */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main(int argc, char *argv[], char *envp[])
        int     fd[2], nbytes, status;
        char    string[] = "Hello, world!\n";

    printf("fd[0] (read): %d, fd[1] (write) %d\n", fd[0], fd[1]);
    write(fd[1], string, (strlen(string)+1));

    status = execve("/home/mfoley/dovecot-checkpassword/checkpassword", argv, envp);
    printf("%d\n", status);

Open in new window

#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>

main(int argc, char *argv[])
    char        buffer[600];
    int         cnt;

/*    if ((argc > 1) && strlen(argv[1])) printf("%s\n", argv[1]);*/

printf("entered checkpassword\n");
    cnt = read(3, buffer, sizeof(buffer));
printf("finished reading\n");
    printf("%d: %s\n", cnt, buffer);
    fprintf(stderr, "ERROR %s\n", strerror(errno));

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
MarkAuthor Commented:
Last bit, do any of you know what the c lib function equivalent for the ntlm_auth command is? Not having much luck googling, but will keep looking.
Kent OlsenDBACommented:
Hi Mark,

I don't think that does what you think it does.

execve() overlays the current task with the program in the call's first parameter.  If the call is successful, the called program becomes the task and there is no return back to the original program.
MarkAuthor Commented:
no, that works fine. My test program that calls execve is simulating the real one in the mail facility. I've bolted my finished checkpassword program into the mail stream and it is getting the right info.

I'll ask my auth lib question in another post. And I'm about to post another C question about setting environment variables. Stay tooned!
MarkAuthor Commented:
I've put together the complete solution.

Thanks all! - couldn't have figured it out without you.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.