├── 1792.pdf
├── 1966.html
├── 9781590593226.jpg
├── AppendixA
├── 3227appa01.c
├── 3227appa02.c
└── 3227appa03.c
├── Chapter02
├── 32270201.c
└── 32270202.c
├── Chapter03
├── 32270301.c
├── 32270302.c
├── 32270303.c
└── 32270304.c
├── Chapter05
├── client.c
├── server1.c
├── server2.c
├── server3.c
├── server4.c
└── server5.c
├── Chapter07
├── daemon.c
└── daemon2.c
├── Chapter09
├── chatcli.tar.gz
└── chatsrv.tar.gz
├── Chapter10
├── bio_client.c
├── bio_server.c
├── fd_client.c
└── fd_server.c
├── Chapter11
└── pamtest.c
├── Chapter13
├── Makefile
├── client
│ ├── Makefile
│ ├── auth_client.c
│ └── auth_client.h
├── common
│ ├── Makefile
│ ├── common.c
│ └── common.h
└── server
│ ├── Makefile
│ ├── auth_server.c
│ └── auth_server.h
├── LICENSE.txt
├── README.md
├── contributing.md
└── server.pem
/1792.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/def-guide-to-linux-network-programming/391555121d25bfa7d296dfd2af42825134cb94ad/1792.pdf
--------------------------------------------------------------------------------
/1966.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/def-guide-to-linux-network-programming/391555121d25bfa7d296dfd2af42825134cb94ad/1966.html
--------------------------------------------------------------------------------
/9781590593226.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/def-guide-to-linux-network-programming/391555121d25bfa7d296dfd2af42825134cb94ad/9781590593226.jpg
--------------------------------------------------------------------------------
/AppendixA/3227appa01.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | const char APRESSMESSAGE[] = "APRESS - For Professionals, By Professionals!\n";
7 |
8 | int main(int argc, char *argv[]) {
9 |
10 | int simpleSocket = 0;
11 | int simplePort = 0;
12 | int returnStatus = 0;
13 | struct sockaddr_in6 simpleServer;
14 |
15 | if (2 != argc) {
16 |
17 | fprintf(stderr, "Usage: %s \n", argv[0]);
18 | exit(1);
19 |
20 | }
21 |
22 | simpleSocket = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
23 |
24 | if (simpleSocket == -1) {
25 |
26 | fprintf(stderr, "Could not create a socket!\n");
27 | exit(1);
28 |
29 | }
30 | else {
31 | fprintf(stderr, "Socket created!\n");
32 | }
33 |
34 | /* retrieve the port number for listening */
35 | simplePort = atoi(argv[1]);
36 |
37 | /* setup the address structure */
38 | /* use INADDR_ANY to bind to all local addresses */
39 | bzero(&simpleServer, sizeof(simpleServer));
40 | simpleServer.sin6_family = PF_INET6;
41 |
42 | inet_pton(PF_INET6, "::1", &(simpleServer.sin6_addr));
43 |
44 | simpleServer.sin6_port = htons(simplePort);
45 |
46 | /* bind to the address and port with our socket */
47 | returnStatus = bind(simpleSocket,(struct sockaddr *)&simpleServer,sizeof(simpleServer));
48 |
49 | if (returnStatus == 0) {
50 | fprintf(stderr, "Bind completed!\n");
51 | }
52 | else {
53 | fprintf(stderr, "Could not bind to address!\n");
54 | close(simpleSocket);
55 | exit(1);
56 | }
57 |
58 | /* lets listen on the socket for connections */
59 | returnStatus = listen(simpleSocket, 5);
60 |
61 | if (returnStatus == -1) {
62 | fprintf(stderr, "Cannot listen on socket!\n");
63 | close(simpleSocket);
64 | exit(1);
65 | }
66 |
67 | while (1)
68 |
69 | {
70 |
71 | struct sockaddr_in6 clientName = { 0 };
72 | int simpleChildSocket = 0;
73 | int clientNameLength = sizeof(clientName);
74 |
75 | /* wait here */
76 |
77 | simpleChildSocket = accept(simpleSocket,(struct sockaddr *)&clientName, &clientNameLength);
78 |
79 | if (simpleChildSocket == -1) {
80 |
81 | fprintf(stderr, "Cannot accept connections!\n");
82 | close(simpleSocket);
83 | exit(1);
84 |
85 | }
86 |
87 | /* handle the new connection request */
88 | /* write out our message to the client */
89 | write(simpleChildSocket, APRESSMESSAGE, strlen(APRESSMESSAGE));
90 | close(simpleChildSocket);
91 |
92 | }
93 |
94 | close(simpleSocket);
95 | return 0;
96 |
97 | }
98 |
99 |
--------------------------------------------------------------------------------
/AppendixA/3227appa02.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | int main(int argc, char *argv[]) {
7 |
8 | int simpleSocket = 0;
9 | int simplePort = 0;
10 | int returnStatus = 0;
11 | char buffer[256] = "";
12 | struct sockaddr_in6 simpleServer;
13 |
14 | if (3 != argc) {
15 |
16 | fprintf(stderr, "Usage: %s \n", argv[0]);
17 | exit(1);
18 |
19 | }
20 |
21 | /* create a streaming socket */
22 | simpleSocket = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
23 |
24 | if (simpleSocket == -1) {
25 |
26 | fprintf(stderr, "Could not create a socket!\n");
27 | exit(1);
28 |
29 | }
30 | else {
31 | fprintf(stderr, "Socket created!\n");
32 | }
33 |
34 | /* retrieve the port number for connecting */
35 | simplePort = atoi(argv[2]);
36 |
37 | /* setup the address structure */
38 | /* use the IP address sent as an argument for the server address */
39 | bzero(&simpleServer, sizeof(simpleServer));
40 | simpleServer.sin6_family = PF_INET6;
41 |
42 | inet_pton(PF_INET6, argv[1], &(simpleServer.sin6_addr));
43 |
44 | /* inet_addr(argv[2], &simpleServer.sin_addr.s_addr); */
45 |
46 | simpleServer.sin6_port = htons(simplePort);
47 |
48 | /* connect to the address and port with our socket */
49 | returnStatus = connect(simpleSocket, (struct sockaddr *)&simpleServer, sizeof(simpleServer));
50 |
51 | if (returnStatus == 0) {
52 | fprintf(stderr, "Connect successful!\n");
53 | }
54 | else {
55 | fprintf(stderr, "Could not connect to address!\n");
56 | close(simpleSocket);
57 | exit(1);
58 | }
59 |
60 | /* get the message from the server */
61 | returnStatus = read(simpleSocket, buffer, sizeof(buffer));
62 |
63 | if ( returnStatus > 0 ) {
64 | printf("%d: %s", returnStatus, buffer);
65 | } else {
66 | fprintf(stderr, "Return Status = %d \n", returnStatus);
67 | }
68 |
69 | close(simpleSocket);
70 | return 0;
71 |
72 | }
73 |
74 |
--------------------------------------------------------------------------------
/AppendixA/3227appa03.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | int main(int argc, char *argv[]) {
7 |
8 | int simpleSocket = 0;
9 | int simplePort = 0;
10 | int returnStatus = 0;
11 | char buffer[256] = "";
12 |
13 | struct addrinfo hints, *res;
14 |
15 | bzero(&hints, sizeof(struct addrinfo));
16 | hints.ai_family = PF_UNSPEC;
17 | /* hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME; */
18 | hints.ai_socktype = SOCK_STREAM;
19 |
20 | if (3 != argc) {
21 |
22 | fprintf(stderr, "Usage: %s \n", argv[0]);
23 | exit(1);
24 |
25 | }
26 |
27 | /* setup the address structure */
28 | returnStatus = getaddrinfo(argv[1], argv[2], &hints, &res);
29 |
30 | if(returnStatus) {
31 |
32 | fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(returnStatus));
33 | exit(1);
34 |
35 | }
36 |
37 | /* create the socket */
38 | simpleSocket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
39 |
40 | if (simpleSocket == -1) {
41 |
42 | fprintf(stderr, "Could not create a socket!\n");
43 | exit(1);
44 |
45 | }
46 | else {
47 | fprintf(stderr, "Socket created!\n");
48 | }
49 |
50 | /* connect to the address and port with our socket */
51 | returnStatus = connect(simpleSocket, res->ai_addr, res->ai_addrlen);
52 |
53 | if (returnStatus == 0) {
54 | fprintf(stderr, "Connect successful!\n");
55 | }
56 | else {
57 | fprintf(stderr, "Could not connect to address!\n");
58 | close(simpleSocket);
59 | exit(1);
60 | }
61 |
62 | /* get the message from the server */
63 | returnStatus = read(simpleSocket, buffer, sizeof(buffer));
64 |
65 | if ( returnStatus > 0 ) {
66 | printf("%d: %s", returnStatus, buffer);
67 | } else {
68 | fprintf(stderr, "Return Status = %d \n", returnStatus);
69 | }
70 |
71 | close(simpleSocket);
72 | freeaddrinfo(res);
73 | return 0;
74 |
75 | }
76 |
77 |
--------------------------------------------------------------------------------
/Chapter02/32270201.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | const char APRESSMESSAGE[] = "APRESS - For Professionals, By Professionals!\n";
7 |
8 | int main(int argc, char *argv[]) {
9 |
10 | int simpleSocket = 0;
11 | int simplePort = 0;
12 | int returnStatus = 0;
13 | struct sockaddr_in simpleServer;
14 |
15 | if (2 != argc) {
16 |
17 | fprintf(stderr, "Usage: %s \n", argv[0]);
18 | exit(1);
19 |
20 | }
21 |
22 | simpleSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
23 |
24 | if (simpleSocket == -1) {
25 |
26 | fprintf(stderr, "Could not create a socket!\n");
27 | exit(1);
28 |
29 | }
30 | else {
31 | fprintf(stderr, "Socket created!\n");
32 | }
33 |
34 | /* retrieve the port number for listening */
35 | simplePort = atoi(argv[1]);
36 |
37 | /* setup the address structure */
38 | /* use INADDR_ANY to bind to all local addresses */
39 | bzero(&simpleServer, sizeof(simpleServer));
40 | simpleServer.sin_family = AF_INET;
41 | simpleServer.sin_addr.s_addr = htonl(INADDR_ANY);
42 | simpleServer.sin_port = htons(simplePort);
43 |
44 | /* bind to the address and port with our socket */
45 | returnStatus = bind(simpleSocket,(struct sockaddr *)&simpleServer,sizeof(simpleServer));
46 |
47 | if (returnStatus == 0) {
48 | fprintf(stderr, "Bind completed!\n");
49 | }
50 | else {
51 | fprintf(stderr, "Could not bind to address!\n");
52 | close(simpleSocket);
53 | exit(1);
54 | }
55 |
56 | /* lets listen on the socket for connections */
57 | returnStatus = listen(simpleSocket, 5);
58 |
59 | if (returnStatus == -1) {
60 | fprintf(stderr, "Cannot listen on socket!\n");
61 | close(simpleSocket);
62 | exit(1);
63 | }
64 |
65 | while (1)
66 |
67 | {
68 |
69 | struct sockaddr_in clientName = { 0 };
70 | int simpleChildSocket = 0;
71 | int clientNameLength = sizeof(clientName);
72 |
73 | /* wait here */
74 |
75 | simpleChildSocket = accept(simpleSocket,(struct sockaddr *)&clientName, &clientNameLength);
76 |
77 | if (simpleChildSocket == -1) {
78 |
79 | fprintf(stderr, "Cannot accept connections!\n");
80 | close(simpleSocket);
81 | exit(1);
82 |
83 | }
84 |
85 | /* handle the new connection request */
86 | /* write out our message to the client */
87 | write(simpleChildSocket, APRESSMESSAGE, strlen(APRESSMESSAGE));
88 | close(simpleChildSocket);
89 |
90 | }
91 |
92 | close(simpleSocket);
93 | return 0;
94 |
95 | }
96 |
97 |
--------------------------------------------------------------------------------
/Chapter02/32270202.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | int main(int argc, char *argv[]) {
7 |
8 | int simpleSocket = 0;
9 | int simplePort = 0;
10 | int returnStatus = 0;
11 | char buffer[256] = "";
12 | struct sockaddr_in simpleServer;
13 |
14 | if (3 != argc) {
15 |
16 | fprintf(stderr, "Usage: %s \n", argv[0]);
17 | exit(1);
18 |
19 | }
20 |
21 | /* create a streaming socket */
22 | simpleSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
23 |
24 | if (simpleSocket == -1) {
25 |
26 | fprintf(stderr, "Could not create a socket!\n");
27 | exit(1);
28 |
29 | }
30 | else {
31 | fprintf(stderr, "Socket created!\n");
32 | }
33 |
34 | /* retrieve the port number for connecting */
35 | simplePort = atoi(argv[2]);
36 |
37 | /* setup the address structure */
38 | /* use the IP address sent as an argument for the server address */
39 | bzero(&simpleServer, sizeof(simpleServer));
40 | simpleServer.sin_family = AF_INET;
41 | inet_addr(argv[2], &simpleServer.sin_addr.s_addr);
42 | simpleServer.sin_port = htons(simplePort);
43 |
44 | /* connect to the address and port with our socket */
45 | returnStatus = connect(simpleSocket, (struct sockaddr *)&simpleServer, sizeof(simpleServer));
46 |
47 | if (returnStatus == 0) {
48 | fprintf(stderr, "Connect successful!\n");
49 | }
50 | else {
51 | fprintf(stderr, "Could not connect to address!\n");
52 | close(simpleSocket);
53 | exit(1);
54 | }
55 |
56 | /* get the message from the server */
57 | returnStatus = read(simpleSocket, buffer, sizeof(buffer));
58 |
59 | if ( returnStatus > 0 ) {
60 | printf("%d: %s", returnStatus, buffer);
61 | } else {
62 | fprintf(stderr, "Return Status = %d \n", returnStatus);
63 | }
64 |
65 | close(simpleSocket);
66 | return 0;
67 |
68 | }
69 |
70 |
--------------------------------------------------------------------------------
/Chapter03/32270301.c:
--------------------------------------------------------------------------------
1 |
2 | /* UDP Server */
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #define MAXBUF 1024
11 |
12 | int main(int argc, char* argv[])
13 | {
14 |
15 | int udpSocket;
16 | int returnStatus = 0;
17 | int addrlen = 0;
18 | struct sockaddr_in udpServer, udpClient;
19 | char buf[MAXBUF];
20 |
21 | /* check for the right number of arguments */
22 | if (argc < 2)
23 | {
24 | fprintf(stderr, "Usage: %s \n", argv[0]);
25 | exit(1);
26 | }
27 |
28 | /* create a socket */
29 | udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
30 |
31 | if (udpSocket == -1)
32 | {
33 | fprintf(stderr, "Could not create a socket!\n");
34 | exit(1);
35 | }
36 | else {
37 | printf("Socket created.\n");
38 | }
39 |
40 | /* setup the server address and port */
41 | /* use INADDR_ANY to bind to all local addresses */
42 | udpServer.sin_family = AF_INET;
43 | udpServer.sin_addr.s_addr = htonl(INADDR_ANY);
44 |
45 | /* use the port pased as argument */
46 | udpServer.sin_port = htons(atoi(argv[1]));
47 |
48 | /* bind to the socket */
49 | returnStatus = bind(udpSocket, (struct sockaddr*)&udpServer, sizeof(udpServer));
50 |
51 | if (returnStatus == 0) {
52 | fprintf(stderr, "Bind completed!\n");
53 | }
54 | else {
55 | fprintf(stderr, "Could not bind to address!\n");
56 | close(udpSocket);
57 | exit(1);
58 | }
59 |
60 | while (1)
61 | {
62 |
63 | addrlen = sizeof(udpClient);
64 |
65 | returnStatus = recvfrom(udpSocket, buf, MAXBUF, 0,
66 | (struct sockaddr*)&udpClient, &addrlen);
67 |
68 | if (returnStatus == -1) {
69 |
70 | fprintf(stderr, "Could not receive message!\n");
71 |
72 | }
73 | else {
74 |
75 | printf("Received: %s\n", buf);
76 |
77 | /* a message was received so send a confirmation */
78 | strcpy(buf, "OK");
79 |
80 | returnStatus = sendto(udpSocket, buf, strlen(buf)+1, 0,
81 | (struct sockaddr*)&udpClient, sizeof(udpClient));
82 |
83 | if (returnStatus == -1) {
84 | fprintf(stderr, "Could not send confirmation!\n");
85 | }
86 | else {
87 | printf("Confirmation sent.\n");
88 |
89 | }
90 | }
91 |
92 | }
93 |
94 | /*cleanup */
95 | close(udpSocket);
96 | return 0;
97 | }
98 |
--------------------------------------------------------------------------------
/Chapter03/32270302.c:
--------------------------------------------------------------------------------
1 |
2 | /* UDP client */
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #define MAXBUF 1024
11 |
12 | int main(int argc, char* argv[])
13 | {
14 |
15 | int udpSocket;
16 | int returnStatus;
17 | int addrlen;
18 | struct sockaddr_in udpClient, udpServer;
19 | char buf[MAXBUF];
20 |
21 | if (argc < 3)
22 | {
23 | fprintf(stderr, "Usage: %s \n", argv[0]);
24 | exit(1);
25 | }
26 |
27 | /* create a socket */
28 | udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
29 |
30 | if (udpSocket == -1)
31 | {
32 | fprintf(stderr, "Could not create a socket!\n");
33 | exit(1);
34 | }
35 | else {
36 | printf("Socket created.\n");
37 | }
38 |
39 | /* client address */
40 | /* use INADDR_ANY to use all local addresses */
41 | udpClient.sin_family = AF_INET;
42 | udpClient.sin_addr.s_addr = INADDR_ANY;
43 | udpClient.sin_port = 0;
44 |
45 | returnStatus = bind(udpSocket, (struct sockaddr*)&udpClient, sizeof(udpClient));
46 |
47 | if (returnStatus == 0) {
48 | fprintf(stderr, "Bind completed!\n");
49 | }
50 | else {
51 | fprintf(stderr, "Could not bind to address!\n");
52 | close(udpSocket);
53 | exit(1);
54 | }
55 |
56 | /* setup the message to be sent to the server */
57 | strcpy(buf, "For Professionals, By Professionals.\n");
58 |
59 | /* server address */
60 | /* use the command line arguments */
61 | udpServer.sin_family = AF_INET;
62 | udpServer.sin_addr.s_addr = inet_addr(argv[1]);
63 | udpServer.sin_port = htons(atoi(argv[2]));
64 |
65 | returnStatus = sendto(udpSocket, buf, strlen(buf)+1, 0,
66 | (struct sockaddr*)&udpServer, sizeof(udpServer));
67 |
68 | if (returnStatus == -1) {
69 | fprintf(stderr, "Could not send message!\n");
70 | }
71 | else {
72 |
73 | printf("Message sent.\n");
74 |
75 | /* message sent: look for confirmation */
76 | addrlen = sizeof(udpServer);
77 |
78 | returnStatus = recvfrom(udpSocket, buf, MAXBUF, 0,
79 | (struct sockaddr*)&udpServer, &addrlen);
80 | if (returnStatus == -1) {
81 | fprintf(stderr, "Did not receive confirmation!\n");
82 | }
83 | else {
84 |
85 | buf[returnStatus] = 0;
86 | printf("Received: %s\n", buf);
87 | }
88 |
89 | }
90 |
91 | /* cleanup */
92 | close(udpSocket);
93 | return 0;
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/Chapter03/32270303.c:
--------------------------------------------------------------------------------
1 |
2 | /* File transfer server */
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #define SERVERPORT 8888
11 | #define MAXBUF 1024
12 |
13 | int main()
14 | {
15 |
16 | int socket1,socket2;
17 | int addrlen;
18 | struct sockaddr_in xferServer, xferClient;
19 | int returnStatus;
20 |
21 | /* create a socket */
22 | socket1 = socket(AF_INET, SOCK_STREAM, 0);
23 |
24 | if (socket1 == -1)
25 | {
26 | fprintf(stderr, "Could not create socket!\n");
27 | exit(1);
28 | }
29 |
30 | /* bind to a socket, use INADDR_ANY for all local addresses */
31 | xferServer.sin_family = AF_INET;
32 | xferServer.sin_addr.s_addr = INADDR_ANY;
33 | xferServer.sin_port = htons(SERVERPORT);
34 |
35 | returnStatus = bind(socket1, (struct sockaddr*)&xferServer, sizeof(xferServer));
36 |
37 | if (returnStatus == -1)
38 | {
39 | fprintf(stderr, "Could not bind to socket!\n");
40 | exit(1);
41 | }
42 |
43 | returnStatus = listen(socket1, 5);
44 |
45 | if (returnStatus == -1)
46 | {
47 | fprintf(stderr, "Could not listen on socket!\n");
48 | exit(1);
49 | }
50 |
51 | for(;;)
52 | {
53 |
54 | int fd;
55 | int i, readCounter, writeCounter;
56 | char* bufptr;
57 | char buf[MAXBUF];
58 | char filename[MAXBUF];
59 |
60 | /* wait for an incoming connection */
61 | addrlen = sizeof(xferClient);
62 |
63 | /* use accept() to handle incoming connection requests */
64 | /* and free up the original socket for other requests */
65 | socket2 = accept(socket1, (struct sockaddr*)&xferClient, &addrlen);
66 |
67 | if (socket2 == -1)
68 | {
69 | fprintf(stderr, "Could not accept connection!\n");
70 | exit(1);
71 | }
72 |
73 | /* get the filename from the client over the socket */
74 | i = 0;
75 |
76 | if ((readCounter = read(socket2, filename + i, MAXBUF)) > 0)
77 | {
78 | i += readCounter;
79 | }
80 |
81 | if (readCounter == -1)
82 | {
83 | fprintf(stderr, "Could not read filename from socket!\n");
84 | close(socket2);
85 | continue;
86 | }
87 |
88 | filename[i+1] = '\0';
89 |
90 | printf("Reading file %s\n", filename);
91 |
92 | /* open the file for reading */
93 | fd = open(filename, O_RDONLY);
94 |
95 | if (fd == -1)
96 | {
97 | fprintf(stderr, "Could not open file for reading!\n");
98 | close(socket2);
99 | continue;
100 | }
101 |
102 | /* reset the read counter */
103 | readCounter = 0;
104 |
105 | /* read the file, and send it to the client in chunks of size MAXBUF */
106 | while((readCounter = read(fd, buf, MAXBUF)) > 0)
107 | {
108 | writeCounter = 0;
109 | bufptr = buf;
110 |
111 | while (writeCounter < readCounter)
112 | {
113 |
114 | readCounter -= writeCounter;
115 | bufptr += writeCounter;
116 | writeCounter = write(socket2, bufptr, readCounter);
117 |
118 | if (writeCounter == -1)
119 | {
120 | fprintf(stderr, "Could not write file to client!\n");
121 | close(socket2);
122 | continue;
123 | }
124 | }
125 | }
126 |
127 | close(socket2);
128 | close(fd);
129 |
130 | }
131 |
132 | close (socket1);
133 | return 0;
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/Chapter03/32270304.c:
--------------------------------------------------------------------------------
1 |
2 | /* File transfer client */
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | #define SERVERPORT 8888
14 | #define MAXBUF 1024
15 |
16 | int main(int argc, char* argv[])
17 | {
18 | int sockd;
19 | int counter;
20 | int fd;
21 | struct sockaddr_in xferServer;
22 | char buf[MAXBUF];
23 | int returnStatus;
24 |
25 | if (argc < 3)
26 | {
27 | fprintf(stderr, "Usage: %s [dest filename]\n", argv[0]);
28 | exit(1);
29 | }
30 |
31 | /* create a socket */
32 | sockd = socket(AF_INET, SOCK_STREAM, 0);
33 |
34 | if (sockd == -1)
35 | {
36 | fprintf(stderr, "Could not create socket!\n");
37 | exit(1);
38 | }
39 |
40 | /* set up the server information */
41 | xferServer.sin_family = AF_INET;
42 | xferServer.sin_addr.s_addr = inet_addr(argv[1]);
43 | xferServer.sin_port = htons(SERVERPORT);
44 |
45 | /* connect to the server */
46 | returnStatus = connect(sockd, (struct sockaddr*)&xferServer, sizeof(xferServer));
47 |
48 | if (returnStatus == -1)
49 | {
50 | fprintf(stderr, "Could not connect to server!\n");
51 | exit(1);
52 | }
53 |
54 | /* send the name of the file we want to the server */
55 | returnStatus = write(sockd, argv[2], strlen(argv[2])+1);
56 |
57 | if (returnStatus == -1)
58 | {
59 | fprintf(stderr, "Could not send filename to server!\n");
60 | exit(1);
61 | }
62 |
63 | /* call the shutdown to set our socket to read only */
64 | shutdown(sockd, SHUT_WR);
65 |
66 | /* open up a handle to our destination file to receive the contents */
67 | /* from the server */
68 | fd = open(argv[3], O_WRONLY | O_CREAT | O_APPEND);
69 |
70 | if (fd == -1)
71 | {
72 | fprintf(stderr, "Could not open destination file, using stdout.\n");
73 | fd = 1;
74 | }
75 |
76 | /* read the file from the socket as long as there is data */
77 | while ((counter = read(sockd, buf, MAXBUF)) > 0)
78 | {
79 | /* send the contents to stdout */
80 | write(fd, buf, counter);
81 | }
82 |
83 | if (counter == -1)
84 | {
85 | fprintf(stderr, "Could not read file from socket!\n");
86 | exit(1);
87 | }
88 |
89 | close(sockd);
90 | return 0;
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/Chapter05/client.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | void child_func(int childnum);
8 |
9 | int main(int argc, char *argv[])
10 | {
11 | int nchildren = 1;
12 | int pid;
13 | int x;
14 |
15 | if (argc > 1) {
16 | nchildren = atoi(argv[1]);
17 | }
18 |
19 | for (x = 0; x < nchildren; x++) {
20 | if ((pid = fork()) == 0) {
21 | child_func(x + 1);
22 | exit(0);
23 | }
24 | }
25 |
26 | wait(NULL);
27 |
28 | return 0;
29 | }
30 |
31 | void child_func(int childnum)
32 | {
33 | int sock;
34 | struct sockaddr_in sAddr;
35 | char buffer[25];
36 | int x;
37 |
38 | sAddr.sin_family = AF_INET;
39 | sAddr.sin_addr.s_addr = INADDR_ANY;
40 | sAddr.sin_port = 0;
41 |
42 | sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
43 | bind(sock, (const struct sockaddr *) &sAddr, sizeof(sAddr));
44 |
45 | sAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
46 | sAddr.sin_port = htons(1972);
47 |
48 | if (connect(sock, (const struct sockaddr *) &sAddr, sizeof(sAddr)) != 0) {
49 | perror("client");
50 | return;
51 | }
52 |
53 | snprintf(buffer, 128, "data from client #%i.", childnum);
54 | sleep(1);
55 | printf("child #%i sent %i chars\n", childnum, send(sock, buffer, strlen(buffer), 0));
56 | sleep(1);
57 | printf("child #%i received %i chars\n", childnum, recv(sock, buffer, 25, 0));
58 | sleep(1);
59 |
60 | close(sock);
61 | }
62 |
--------------------------------------------------------------------------------
/Chapter05/server1.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | int main(int argc, char *argv[])
8 | {
9 | struct sockaddr_in sAddr;
10 | fd_set readset, testset;
11 | int listensock;
12 | int newsock;
13 | char buffer[25];
14 | int result;
15 | int nread;
16 | int x;
17 | int val;
18 |
19 | listensock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
20 |
21 | val = 1;
22 | result = setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
23 | if (result < 0) {
24 | perror("server1");
25 | return 0;
26 | }
27 |
28 | sAddr.sin_family = AF_INET;
29 | sAddr.sin_port = htons(1972);
30 | sAddr.sin_addr.s_addr = INADDR_ANY;
31 |
32 | result = bind(listensock, (struct sockaddr *) &sAddr, sizeof(sAddr));
33 | if (result < 0) {
34 | perror("server1");
35 | return 0;
36 | }
37 |
38 | result = listen(listensock, 5);
39 | if (result < 0) {
40 | perror("server1");
41 | return 0;
42 | }
43 |
44 | FD_ZERO(&readset);
45 | FD_SET(listensock, &readset);
46 |
47 | while (1) {
48 | testset = readset;
49 | result = select(FD_SETSIZE, &testset, NULL, NULL, NULL);
50 | if (result < 1) {
51 | perror("server1");
52 | return 0;
53 | }
54 | for (x = 0; x < FD_SETSIZE; x++) {
55 | if (FD_ISSET(x, &testset)) {
56 | if (x == listensock) {
57 | newsock = accept(listensock, NULL ,NULL);
58 | FD_SET(newsock, &readset);
59 | } else {
60 | nread = recv(x, buffer, 25, 0);
61 | if (nread <= 0) {
62 | close(x);
63 | FD_CLR(x, &readset);
64 | printf("client on descriptor #%i disconnected\n", x);
65 | } else {
66 | buffer[nread] = '\0';
67 | printf("%s\n", buffer);
68 | send(x, buffer, nread, 0);
69 | }
70 | }
71 | }
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/Chapter05/server2.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | void sigchld_handler(int signo)
10 | {
11 | while (waitpid(-1, NULL, WNOHANG) > 0);
12 | }
13 |
14 | int main(int argc, char *argv[])
15 | {
16 | struct sockaddr_in sAddr;
17 | int listensock;
18 | int newsock;
19 | char buffer[25];
20 | int result;
21 | int nread;
22 | int pid;
23 | int val;
24 |
25 | listensock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
26 |
27 | val = 1;
28 | result = setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
29 | if (result < 0) {
30 | perror("server2");
31 | return 0;
32 | }
33 |
34 | sAddr.sin_family = AF_INET;
35 | sAddr.sin_port = htons(1972);
36 | sAddr.sin_addr.s_addr = INADDR_ANY;
37 |
38 | result = bind(listensock, (struct sockaddr *) &sAddr, sizeof(sAddr));
39 | if (result < 0) {
40 | perror("exserver2");
41 | return 0;
42 | }
43 |
44 | result = listen(listensock, 5);
45 | if (result < 0) {
46 | perror("exserver2");
47 | return 0;
48 | }
49 |
50 | signal(SIGCHLD, sigchld_handler);
51 |
52 | while (1) {
53 | newsock = accept(listensock, NULL ,NULL);
54 | if ((pid = fork()) == 0) {
55 | printf("child process %i created.\n", getpid());
56 | close(listensock);
57 | nread = recv(newsock, buffer, 25, 0);
58 | buffer[nread] = '\0';
59 | printf("%s\n", buffer);
60 | send(newsock, buffer, nread, 0);
61 | close(newsock);
62 | printf("child process %i finished.\n", getpid());
63 | exit(0);
64 | }
65 | close(newsock);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Chapter05/server3.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | int main(int argc, char *argv[])
8 | {
9 | struct sockaddr_in sAddr;
10 | int listensock;
11 | int newsock;
12 | char buffer[25];
13 | int result;
14 | int nread;
15 | int pid;
16 | int nchildren = 1;
17 | int x;
18 | int val;
19 |
20 | if (argc > 1) {
21 | nchildren = atoi(argv[1]);
22 | }
23 |
24 | listensock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
25 |
26 | val = 1;
27 | result = setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
28 | if (result < 0) {
29 | perror("server3");
30 | return 0;
31 | }
32 |
33 | sAddr.sin_family = AF_INET;
34 | sAddr.sin_port = htons(1972);
35 | sAddr.sin_addr.s_addr = INADDR_ANY;
36 |
37 | result = bind(listensock, (struct sockaddr *) &sAddr, sizeof(sAddr));
38 | if (result < 0) {
39 | perror("exserver3");
40 | return 0;
41 | }
42 |
43 | result = listen(listensock, 5);
44 | if (result < 0) {
45 | perror("exserver3");
46 | return 0;
47 | }
48 |
49 | for (x = 0; x < nchildren; x++) {
50 | if ((pid = fork()) == 0) {
51 | while (1) {
52 | newsock = accept(listensock, NULL ,NULL);
53 | printf("client connected to child process %i.\n", getpid());
54 | nread = recv(newsock, buffer, 25, 0);
55 | buffer[nread] = '\0';
56 | printf("%s\n", buffer);
57 | send(newsock, buffer, nread, 0);
58 | close(newsock);
59 | printf("client disconnected from child process %i.\n", getpid());
60 | }
61 | }
62 | }
63 |
64 | wait(NULL);
65 | }
66 |
--------------------------------------------------------------------------------
/Chapter05/server4.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | void* thread_proc(void *arg);
9 |
10 | int main(int argc, char *argv[])
11 | {
12 | struct sockaddr_in sAddr;
13 | int listensock;
14 | int newsock;
15 | int result;
16 | pthread_t thread_id;
17 | int val;
18 |
19 | listensock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
20 |
21 | val = 1;
22 | result = setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
23 | if (result < 0) {
24 | perror("server4");
25 | return 0;
26 | }
27 |
28 | sAddr.sin_family = AF_INET;
29 | sAddr.sin_port = htons(1972);
30 | sAddr.sin_addr.s_addr = INADDR_ANY;
31 |
32 | result = bind(listensock, (struct sockaddr *) &sAddr, sizeof(sAddr));
33 | if (result < 0) {
34 | perror("exserver4");
35 | return 0;
36 | }
37 |
38 | result = listen(listensock, 5);
39 | if (result < 0) {
40 | perror("exserver4");
41 | return 0;
42 | }
43 |
44 | while (1) {
45 | newsock = accept(listensock, NULL ,NULL);
46 | result = pthread_create(&thread_id, NULL, thread_proc, (void *) newsock);
47 | if (result != 0) {
48 | printf("Could not create thread.\n");
49 | return 0;
50 | }
51 | pthread_detach(thread_id);
52 | sched_yield();
53 | }
54 | }
55 |
56 | void* thread_proc(void *arg)
57 | {
58 | int sock;
59 | char buffer[25];
60 | int nread;
61 |
62 | printf("child thread %i with pid %i created.\n", pthread_self(), getpid());
63 | sock = (int) arg;
64 | nread = recv(sock, buffer, 25, 0);
65 | buffer[nread] = '\0';
66 | printf("%s\n", buffer);
67 | send(sock, buffer, nread, 0);
68 | close(sock);
69 | printf("child thread %i with pid %i finished.\n", pthread_self(), getpid());
70 | }
71 |
--------------------------------------------------------------------------------
/Chapter05/server5.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | void* thread_proc(void *arg);
9 |
10 | int main(int argc, char *argv[])
11 | {
12 | struct sockaddr_in sAddr;
13 | int listensock;
14 | int result;
15 | int nchildren = 1;
16 | pthread_t thread_id;
17 | int x;
18 | int val;
19 |
20 | if (argc > 1) {
21 | nchildren = atoi(argv[1]);
22 | }
23 |
24 | listensock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
25 |
26 | val = 1;
27 | result = setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
28 | if (result < 0) {
29 | perror("server5");
30 | return 0;
31 | }
32 |
33 | sAddr.sin_family = AF_INET;
34 | sAddr.sin_port = htons(1972);
35 | sAddr.sin_addr.s_addr = INADDR_ANY;
36 |
37 | result = bind(listensock, (struct sockaddr *) &sAddr, sizeof(sAddr));
38 | if (result < 0) {
39 | perror("exserver5");
40 | return 0;
41 | }
42 |
43 | result = listen(listensock, 5);
44 | if (result < 0) {
45 | perror("exserver5");
46 | return 0;
47 | }
48 |
49 | for (x = 0; x < nchildren; x++) {
50 | result = pthread_create(&thread_id, NULL, thread_proc, (void *) listensock);
51 | if (result != 0) {
52 | printf("Could not create thread.\n");
53 | return 0;
54 | }
55 | sched_yield();
56 | }
57 |
58 | pthread_join (thread_id, NULL);
59 | }
60 |
61 | void* thread_proc(void *arg)
62 | {
63 | int listensock, sock;
64 | char buffer[25];
65 | int nread;
66 |
67 | listensock = (int) arg;
68 |
69 | while (1) {
70 | sock = accept(listensock, NULL, NULL);
71 | printf("client connected to child thread %i with pid %i.\n", pthread_self(), getpid());
72 | nread = recv(sock, buffer, 25, 0);
73 | buffer[nread] = '\0';
74 | printf("%s\n", buffer);
75 | send(sock, buffer, nread, 0);
76 | close(sock);
77 | printf("client disconnected from child thread %i with pid %i.\n", pthread_self(), getpid());
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Chapter07/daemon.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 |
6 | int daemonize()
7 | {
8 | pid_t pid;
9 | long n_desc;
10 | int i;
11 |
12 | if ((pid = fork()) != 0) {
13 | exit(0);
14 | }
15 |
16 | setsid();
17 |
18 | if ((pid = fork()) != 0) {
19 | exit(0);
20 | }
21 |
22 | chdir("/");
23 | umask(0);
24 |
25 | n_desc = sysconf(_SC_OPEN_MAX);
26 | for (i = 0; i < n_desc; i++) {
27 | close(i);
28 | }
29 |
30 | return 1;
31 | }
32 |
33 | int main(int argc, char **argv)
34 | {
35 | daemonize();
36 |
37 | openlog("test_daemon", LOG_PID, LOG_USER);
38 | syslog(LOG_INFO, "%s", "Hello World!");
39 | closelog();
40 |
41 | return 1;
42 | }
43 |
--------------------------------------------------------------------------------
/Chapter07/daemon2.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | int daemonize()
7 | {
8 | pid_t pid;
9 | long n_desc;
10 | int i;
11 |
12 | if ((pid = fork()) != 0) {
13 | exit(0);
14 | }
15 |
16 | setsid();
17 |
18 | if ((pid = fork()) != 0) {
19 | exit(0);
20 | }
21 |
22 | chdir("/");
23 | umask(0);
24 |
25 | n_desc = sysconf(_SC_OPEN_MAX);
26 | for (i = 0; i < n_desc; i++) {
27 | close(i);
28 | }
29 |
30 | return 1;
31 | }
32 |
33 | int main(int argc, char **argv)
34 | {
35 | struct passwd *pws;
36 | const char *user = "nopriv";
37 |
38 | pws = getpwnam(user);
39 | if (pws == NULL) {
40 | printf("Unknown user: %s\n", user);
41 | return 0;
42 | }
43 |
44 | daemonize();
45 |
46 | setuid(pws->pw_uid);
47 |
48 | while (1) {
49 | sleep(1);
50 | }
51 |
52 | return 1;
53 | }
54 |
--------------------------------------------------------------------------------
/Chapter09/chatcli.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/def-guide-to-linux-network-programming/391555121d25bfa7d296dfd2af42825134cb94ad/Chapter09/chatcli.tar.gz
--------------------------------------------------------------------------------
/Chapter09/chatsrv.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/def-guide-to-linux-network-programming/391555121d25bfa7d296dfd2af42825134cb94ad/Chapter09/chatsrv.tar.gz
--------------------------------------------------------------------------------
/Chapter10/bio_client.c:
--------------------------------------------------------------------------------
1 | /**
2 | Professional Linux Network Programming - Chapter 10 - server.c
3 | By Nathan Yocom, nate@yocom.org
4 | */
5 |
6 | /*
7 | Standard includes
8 | */
9 | #include
10 | #include
11 | #include
12 | #include
13 | /*
14 | SSL includes
15 | */
16 | #include
17 | #include
18 |
19 | int main(int argc, char *argv[]) {
20 | SSL_METHOD *my_ssl_method;
21 | SSL_CTX *my_ssl_ctx;
22 | SSL *my_ssl;
23 | BIO *my_bio;
24 | int error = 0, read_in = 0;
25 | char buffer[512];
26 |
27 | memset(buffer,'\0',sizeof(buffer));
28 |
29 | OpenSSL_add_all_algorithms();
30 | SSL_load_error_strings();
31 |
32 | my_ssl_method = TLSv1_client_method();
33 |
34 | if((my_ssl_ctx = SSL_CTX_new(my_ssl_method)) == NULL) {
35 | ERR_print_errors_fp(stderr);
36 | exit(-1);
37 | }
38 |
39 | if((my_ssl = SSL_new(my_ssl_ctx)) == NULL) {
40 | ERR_print_errors_fp(stderr);
41 | exit(-1);
42 | }
43 |
44 | if((my_bio = BIO_new_connect("127.0.0.1:5353")) == NULL) {
45 | ERR_print_errors_fp(stderr);
46 | exit(-1);
47 | }
48 |
49 | if(BIO_do_connect(my_bio) <=0) {
50 | ERR_print_errors_fp(stderr);
51 | exit(-1);
52 | }
53 |
54 | SSL_set_bio(my_ssl,my_bio,my_bio);
55 |
56 | if(SSL_connect(my_ssl) <= 0) {
57 | ERR_print_errors_fp(stderr);
58 | exit(-1);
59 | }
60 |
61 | printf("Connection made with [version,cipher]: [%s,%s]\n",SSL_get_version(my_ssl),SSL_get_cipher(my_ssl));
62 |
63 | for( read_in = 0; read_in < sizeof(buffer); read_in += error ) {
64 | error = SSL_read(my_ssl,buffer+read_in,sizeof(buffer) - read_in);
65 | if(error <= 0)
66 | break;
67 | }
68 |
69 | SSL_shutdown(my_ssl);
70 | SSL_free(my_ssl);
71 | SSL_CTX_free(my_ssl_ctx);
72 |
73 | printf("%s",buffer);
74 |
75 | return 0;
76 |
77 | report_error("Report error (not quit) test\n",__FILE__,__LINE__,0);
78 | report_error_q("Report error (quit) test\n",__FILE__,__LINE__,0);
79 | return 0;
80 | }
81 |
--------------------------------------------------------------------------------
/Chapter10/bio_server.c:
--------------------------------------------------------------------------------
1 | /**
2 | Professional Linux Network Programming - Chapter 8 - server.c
3 | By Nathan Yocom, plnp@yocom.org
4 | */
5 |
6 | /*
7 | Standard includes
8 | */
9 | #include
10 | #include
11 | #include
12 | #include
13 | /*
14 | SSL includes
15 | */
16 | #include
17 | #include
18 |
19 | int main(int argc, char *argv[]) {
20 | SSL_METHOD *my_ssl_method;
21 | SSL_CTX *my_ssl_ctx;
22 | SSL *my_ssl;
23 | BIO *server_bio,*client_bio;
24 | int error = 0, wrote = 0;
25 | char buffer[] = "Hello there! Welcome to the SSL test server.\n\n";
26 |
27 | OpenSSL_add_all_algorithms();
28 | SSL_load_error_strings();
29 |
30 | my_ssl_method = TLSv1_server_method();
31 |
32 | if((my_ssl_ctx = SSL_CTX_new(my_ssl_method)) == NULL) {
33 | ERR_print_errors_fp(stderr);
34 | exit(-1);
35 | }
36 |
37 | SSL_CTX_use_certificate_file(my_ssl_ctx,"server.pem",SSL_FILETYPE_PEM);
38 | SSL_CTX_use_PrivateKey_file(my_ssl_ctx,"server.pem",SSL_FILETYPE_PEM);
39 |
40 | if(!SSL_CTX_check_private_key(my_ssl_ctx)) {
41 | fprintf(stderr,"Private key does not match certificate\n");
42 | exit(-1);
43 | }
44 |
45 | if((server_bio = BIO_new_accept("5353")) == NULL) {
46 | ERR_print_errors_fp(stderr);
47 | exit(-1);
48 | }
49 |
50 | if(BIO_do_accept(server_bio) <= 0) {
51 | ERR_print_errors_fp(stderr);
52 | exit(-1);
53 | }
54 |
55 | for(;;) {
56 | if(BIO_do_accept(server_bio) <= 0) {
57 | ERR_print_errors_fp(stderr);
58 | exit(-1);
59 | }
60 |
61 | client_bio = BIO_pop(server_bio);
62 |
63 | if((my_ssl = SSL_new(my_ssl_ctx)) == NULL) {
64 | ERR_print_errors_fp(stderr);
65 | exit(-1);
66 | }
67 |
68 | SSL_set_bio(my_ssl,client_bio,client_bio);
69 |
70 | if(SSL_accept(my_ssl) <= 0) {
71 | ERR_print_errors_fp(stderr);
72 | exit(-1);
73 | }
74 |
75 | printf("Connection made with [version,cipher]: [%s,%s]\n",SSL_get_version(my_ssl),SSL_get_cipher(my_ssl));
76 |
77 | for(wrote = 0; wrote < strlen(buffer); wrote += error) {
78 | error = SSL_write(my_ssl,buffer+wrote,strlen(buffer)-wrote);
79 |
80 | if(error <= 0)
81 | break;
82 | }
83 |
84 | SSL_shutdown(my_ssl);
85 | SSL_free(my_ssl);
86 | }
87 |
88 | SSL_CTX_free(my_ssl_ctx);
89 | SSL_BIO_free(server_bio);
90 |
91 | return 0;
92 | }
93 |
--------------------------------------------------------------------------------
/Chapter10/fd_client.c:
--------------------------------------------------------------------------------
1 | /**
2 | Professional Linux Network Programming - Chapter 8 - server.c
3 | By Nathan Yocom, plnp@yocom.org
4 | */
5 |
6 | /*
7 | Standard includes
8 | */
9 | #include
10 | #include
11 | #include
12 | #include
13 | /*
14 | Socket includes
15 | */
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | /*
23 | SSL includes
24 | */
25 | #include
26 | #include
27 |
28 | int main(int argc, char *argv[]) {
29 | SSL_METHOD *my_ssl_method;
30 | SSL_CTX *my_ssl_ctx;
31 | SSL *my_ssl;
32 | int my_fd;
33 | struct sockaddr_in server;
34 | int error = 0, read_in = 0;
35 | char buffer[512];
36 |
37 | memset(buffer,'\0',sizeof(buffer));
38 |
39 | OpenSSL_add_all_algorithms();
40 | SSL_load_error_strings();
41 |
42 | my_ssl_method = TLSv1_client_method();
43 |
44 | if((my_ssl_ctx = SSL_CTX_new(my_ssl_method)) == NULL) {
45 | ERR_print_errors_fp(stderr);
46 | exit(-1);
47 | }
48 |
49 | if((my_ssl = SSL_new(my_ssl_ctx)) == NULL) {
50 | ERR_print_errors_fp(stderr);
51 | exit(-1);
52 | }
53 |
54 | my_fd = socket(AF_INET, SOCK_STREAM, 0);
55 | bzero(&server,sizeof(server));
56 | server.sin_family = AF_INET;
57 | server.sin_port = htons(5353);
58 | inet_aton("127.0.0.1",&server.sin_addr);
59 | bind(my_fd, (struct sockaddr *)&server, sizeof(server));
60 | connect(my_fd,(struct sockaddr *)&server, sizeof(server));
61 |
62 |
63 | SSL_set_fd(my_ssl,my_fd);
64 |
65 | if(SSL_connect(my_ssl) <= 0) {
66 | ERR_print_errors_fp(stderr);
67 | exit(-1);
68 | }
69 |
70 | printf("Connection made with [version,cipher]: [%s,%s]\n",SSL_get_version(my_ssl),SSL_get_cipher(my_ssl));
71 |
72 | for( read_in = 0; read_in < sizeof(buffer); read_in += error ) {
73 | error = SSL_read(my_ssl,buffer+read_in,sizeof(buffer) - read_in);
74 | if(error <= 0)
75 | break;
76 | }
77 |
78 | SSL_shutdown(my_ssl);
79 | SSL_free(my_ssl);
80 | SSL_CTX_free(my_ssl_ctx);
81 | close(my_fd);
82 |
83 | printf("%s",buffer);
84 |
85 | return 0;
86 | }
87 |
--------------------------------------------------------------------------------
/Chapter10/fd_server.c:
--------------------------------------------------------------------------------
1 | /**
2 | Professional Linux Network Programming - Chapter 8 - server.c
3 | By Nathan Yocom, plnp@yocom.org
4 | */
5 |
6 | /*
7 | Standard includes
8 | */
9 | #include
10 | #include
11 | #include
12 | #include
13 | /*
14 | Socket includes
15 | */
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | /*
23 | SSL includes
24 | */
25 | #include
26 | #include
27 |
28 | int main(int argc, char *argv[]) {
29 | SSL_METHOD *my_ssl_method; // The SSL/TLS method to negotiate
30 | SSL_CTX *my_ssl_ctx; // The CTX object for SSL
31 | SSL *my_ssl; // The actual SSL connection
32 | int my_fd,client_fd;
33 | struct sockaddr_in server, client;
34 | int client_size;
35 | int error = 0, wrote = 0;
36 | char buffer[] = "Hello there! Welcome to the SSL test server.\n\n";
37 |
38 | OpenSSL_add_all_algorithms(); // Initialize the OpenSSL library
39 | SSL_load_error_strings(); // Have the OpenSSL library load its error strings
40 |
41 | my_ssl_method = TLSv1_server_method();
42 |
43 | if((my_ssl_ctx = SSL_CTX_new(my_ssl_method)) == NULL) {
44 | ERR_print_errors_fp(stderr);
45 | exit(-1);
46 | }
47 |
48 | SSL_CTX_use_certificate_file(my_ssl_ctx,"server.pem",SSL_FILETYPE_PEM);
49 | SSL_CTX_use_PrivateKey_file(my_ssl_ctx,"server.pem",SSL_FILETYPE_PEM);
50 |
51 | if(!SSL_CTX_check_private_key(my_ssl_ctx)) {
52 | fprintf(stderr,"Private key does not match certificate\n");
53 | exit(-1);
54 | }
55 |
56 | my_fd = socket(PF_INET, SOCK_STREAM, 0);
57 | server.sin_family = AF_INET;
58 | server.sin_port = htons(5353);
59 | server.sin_addr.s_addr = INADDR_ANY;
60 | bind(my_fd, (struct sockaddr *)&server, sizeof(server));
61 | listen(my_fd, 5);
62 |
63 | for(;;) {
64 | client_size = sizeof(client);
65 | bzero(&client,sizeof(client));
66 | client_fd = accept(my_fd, (struct sockaddr *)&client, (socklen_t *)&client_size);
67 |
68 | if((my_ssl = SSL_new(my_ssl_ctx)) == NULL) {
69 | ERR_print_errors_fp(stderr);
70 | exit(-1);
71 | }
72 |
73 | SSL_set_fd(my_ssl,client_fd);
74 |
75 | if(SSL_accept(my_ssl) <= 0) {
76 | ERR_print_errors_fp(stderr);
77 | exit(-1);
78 | }
79 |
80 | printf("Connection made with [version,cipher]: [%s,%s]\n",SSL_get_version(my_ssl),SSL_get_cipher(my_ssl));
81 |
82 | for(wrote = 0; wrote < strlen(buffer); wrote += error) {
83 | error = SSL_write(my_ssl,buffer+wrote,strlen(buffer)-wrote);
84 |
85 | if(error <= 0)
86 | break;
87 | }
88 |
89 | SSL_shutdown(my_ssl);
90 |
91 | SSL_free(my_ssl);
92 | close(client_fd);
93 | }
94 |
95 | SSL_CTX_free(my_ssl_ctx);
96 |
97 | return 0;
98 | }
99 |
--------------------------------------------------------------------------------
/Chapter11/pamtest.c:
--------------------------------------------------------------------------------
1 | /**
2 | Chapter 11 - PAM Authentication - PAM Aware Application Programming
3 | By Nathan Yocom, nate@yocom.org
4 | */
5 |
6 | #include
7 | #include
8 |
9 | int my_conv(int, const struct pam_message **, struct pam_response **, void *);
10 |
11 | static struct pam_conv conv = {
12 | my_conv,
13 | NULL
14 | };
15 |
16 | int my_conv(int num_msg,const struct pam_message **msg, struct pam_response **response, void *appdata_ptr) {
17 | struct pam_response *reply_with = NULL;
18 | int num_replies;
19 | char buffer[80];
20 |
21 | if( num_msg <= 0 )
22 | return PAM_CONV_ERR;
23 |
24 | reply_with = (struct pam_response *)calloc(num_msg, sizeof(struct pam_response));
25 |
26 | if( reply_with == NULL )
27 | return PAM_SYSTEM_ERR;
28 |
29 | memset(buffer,'\0',sizeof(buffer));
30 |
31 | for( num_replies = 0; num_replies < num_msg; num_replies++ ) {
32 | if( msg[num_replies]->msg_style == PAM_PROMPT_ECHO_OFF ) {
33 | reply_with[num_replies].resp_retcode = PAM_SUCCESS;
34 | printf("What is your password? ");
35 | scanf("%s",buffer);
36 | reply_with[num_replies].resp = (char *)strdup(buffer);
37 | } else if( msg[num_replies]->msg_style == PAM_PROMPT_ECHO_ON ) {
38 | reply_with[num_replies].resp_retcode = PAM_SUCCESS;
39 | printf("What is your username? ");
40 | scanf("%s",buffer);
41 | reply_with[num_replies].resp = (char *)strdup(buffer);
42 | } else {
43 | free(reply_with);
44 | return PAM_CONV_ERR;
45 | }
46 | }
47 |
48 | *response = reply_with;
49 | return PAM_SUCCESS;
50 | }
51 |
52 | int main(int argc, char *argv[]) {
53 | pam_handle_t *pamh=NULL;
54 | int ret;
55 | int authenticated = 0;
56 |
57 | if( (ret = pam_start("login", NULL, &conv, &pamh)) == PAM_SUCCESS )
58 | if( (ret = pam_authenticate(pamh, 0)) == PAM_SUCCESS )
59 | if( (ret = pam_acct_mgmt(pamh, 0)) == PAM_SUCCESS )
60 | authenticated = 1;
61 |
62 | if(authenticated)
63 | printf("Authenticated\n");
64 | else
65 | printf("Not Authenticated\n");
66 |
67 | if( pam_end(pamh,ret) != PAM_SUCCESS ) {
68 | pamh = NULL;
69 | printf("Failed to release pam...\n");
70 | exit(1);
71 | }
72 |
73 | if( ret == PAM_SUCCESS )
74 | return 0;
75 | else
76 | return 1;
77 | }
78 |
79 |
80 |
--------------------------------------------------------------------------------
/Chapter13/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | make -C common/
3 | make -C client/
4 | make -C server/
5 |
6 | clean:
7 | make -C common/ clean
8 | make -C client/ clean
9 | make -C server/ clean
10 |
11 |
--------------------------------------------------------------------------------
/Chapter13/client/Makefile:
--------------------------------------------------------------------------------
1 | CC = gcc -Wall
2 | COMMONDIR = ../common
3 | COMMONLIB = $(COMMONDIR)/common.o
4 |
5 | INCLUDES = -I$(COMMONDIR) -I./
6 |
7 | LIBS = $(COMMONLIB)
8 | LIBS += -lcrypto -lssl
9 |
10 | CFLAGS += $(INCLUDES)
11 |
12 | .c.o:
13 | $(CC) $(CFLAGS) $(INCLUDES) -c $<
14 |
15 | BINS = auth_client
16 |
17 | all: libs $(BINS)
18 |
19 | libs:
20 | make -C $(COMMONDIR)
21 |
22 | auth_client.o: auth_client.c auth_client.h $(COMMONLIB)
23 | $(CC) -c $(CFLAGS) auth_client.c
24 |
25 | auth_client: auth_client.o
26 | $(CC) -o auth_client auth_client.o $(LIBS)
27 |
28 | clean:
29 | rm -f *.o
30 | rm -f $(BINS)
31 | make -C $(COMMONDIR) clean
32 |
33 |
--------------------------------------------------------------------------------
/Chapter13/client/auth_client.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Authentication Client - For testing of the Authentication Server
3 | * By Nathan Yocom, 2004 - For APress Book "The Definitive Guide to Linux Network Programming"
4 | *
5 | * auth_client.c = Main client source
6 | */
7 |
8 | #include "common.h"
9 | #include "auth_client.h"
10 |
11 | /**
12 | * Attempt to connect with TLSv1 to the given host on the given port and return an SSL * handle to
13 | * the resulting connection, or NULL on error. If an error occurs, ERR_get_error() can be used
14 | * in conjunction with ERR_error_string() to examine the error in the calling function.
15 | *
16 | * @param host A string indicating the hostname or IP to connect to
17 | * @param port A string indicating the port to connect to the host on
18 | *
19 | * @return An SSL * handle to an active TLSv1 connection, or NULL on error
20 | */
21 | SSL * ssl_client_connect(const char *host, const char *port) {
22 | SSL_METHOD *my_ssl_method; // The method for connection, we use TLSv1
23 | SSL_CTX *my_ssl_ctx; // Our context
24 | SSL *my_ssl; // The SSL pointer we will return
25 | BIO *my_bio; // The BIO used to setup the connection
26 | char *host_port; // A buffer to store the concatenated host:port string
27 |
28 | host_port = w_malloc(strlen(host) + strlen(port) + 2); // Allocate room for "host:port"
29 | sprintf(host_port,"%s:%s",host,port); // And store it formatted
30 |
31 | my_ssl_method = TLSv1_client_method(); // Set our method to TLSv1
32 |
33 | if((my_ssl_ctx = SSL_CTX_new(my_ssl_method)) == NULL) {
34 | return NULL; // If we can't create a context, return NULL
35 | }
36 |
37 | if((my_ssl = SSL_new(my_ssl_ctx)) == NULL) {
38 | SSL_CTX_free(my_ssl_ctx); // If we had problems, free the memory we already setup
39 | return NULL; // and return NULL
40 | }
41 |
42 | if((my_bio = BIO_new_connect(host_port)) == NULL) {
43 | SSL_free(my_ssl); // If we had problems, free the memory we already setup
44 | w_free(host_port);
45 | return NULL; // and return NULL
46 | }
47 |
48 | if(BIO_do_connect(my_bio) <=0) {
49 | SSL_free(my_ssl); // If we had problems, free the memory we already setup
50 | BIO_free(my_bio);
51 | w_free(host_port);
52 | return NULL; // and return NULL
53 | }
54 |
55 | SSL_set_bio(my_ssl,my_bio,my_bio); // Associate our BIO with the SSL handle as both the read and write pipes
56 |
57 | if(SSL_connect(my_ssl) <= 0) {
58 | SSL_free(my_ssl); // If we had problems, free the memory we already setup
59 | w_free(host_port);
60 | return NULL; // and return NULL
61 | }
62 |
63 | w_free(host_port); // Free the space we setup for the host:port string
64 | return my_ssl; // Return the actual connection (all is well)
65 | }
66 |
67 | /**
68 | * This function iterates through the password file using getpwent() looking for a username
69 | * with the same uid as the userid our process has. This way we can lookup our username without
70 | * requiring user input. The result is stored in a static buffer which will be destroyed and overwritten
71 | * with subsequent calls.
72 | *
73 | * @return A string representation of the current username or NULL if not found
74 | */
75 | const char *getUsername(void) {
76 | static char *username_buffer = NULL;
77 | uid_t my_uid;
78 | struct passwd *current_pwent = NULL;
79 |
80 | my_uid = getuid(); // Get our UID
81 | current_pwent = getpwent(); // Get the first passwd file entry
82 |
83 | if(username_buffer != NULL) { // Clear the username buffer if we have been called before
84 | w_free(username_buffer);
85 | username_buffer = NULL;
86 | }
87 |
88 | while(current_pwent && !username_buffer) { // Loop through each entry in the file until we have found or hit EOF
89 | if(current_pwent->pw_uid == my_uid) { // if the UID of this entry matches ours, its our entry
90 | username_buffer = (char *)w_malloc(strlen(current_pwent->pw_name) + 1); // Allocate room for the username
91 | strncpy(username_buffer,current_pwent->pw_name,strlen(current_pwent->pw_name) + 1); // Copy the username in
92 | }
93 | current_pwent = getpwent(); // Get the next passwd file entry
94 | }
95 |
96 | endpwent(); // Make sure we close our access to the pwents
97 | return username_buffer;
98 | }
99 |
100 | /**
101 | * Similar to getUsername, this function iterates through with getpwent looking for our user's home directory
102 | * and returns that directory in a static char buffer that will be overwritten with subsequent calls.
103 | *
104 | * @param username The username to look for a home dir value
105 | * @return The users home directory as a null terminated string, or NULL of not found
106 | */
107 | const char *getUsersHome(const char *username) {
108 | static char *home_buffer = NULL;
109 | struct passwd *current_pwent = NULL;
110 |
111 | current_pwent = getpwent(); // Get the first passwd file entry
112 |
113 | if(home_buffer != NULL) { // Clear the username buffer if we have been called before
114 | w_free(home_buffer);
115 | home_buffer = NULL;
116 | }
117 |
118 | while(current_pwent) { // Loop through each entry in the file until we have found or hit EOF
119 | if(strcasecmp(username,current_pwent->pw_name) == 0) { // if the usernames match
120 | home_buffer = (char *)w_malloc(strlen(current_pwent->pw_dir) + 1); // Allocate room for the username
121 | strncpy(home_buffer,current_pwent->pw_dir,strlen(current_pwent->pw_dir) + 1); // Copy the username in
122 | }
123 | current_pwent = getpwent(); // Get the next passwd file entry
124 | }
125 |
126 | endpwent(); // make sure we close our access to the pwents
127 | return home_buffer; // Return the result
128 | }
129 |
130 | /**
131 | * Check the users home directory for a key file that is named .[host].priv which will contain
132 | * the users private RSA key for authentication with the given host.
133 | *
134 | * @param host Hostname to look for
135 | * @param username The username we are running as
136 | * @return 0 on success, -1 on failure
137 | */
138 | int haveServerKey(const char *host,const char *username) {
139 | char *file_path = NULL; // Buffer where we will build the path
140 | const char *user_home = NULL; // The user's home directory
141 | FILE *key_file = NULL; // File pointer used to check for file existence
142 |
143 | if((user_home = getUsersHome(username)) == NULL) {
144 | report_error_q("Unable to find user's home directory",__FILE__,__LINE__,0);
145 | }
146 |
147 | file_path = (char *)w_malloc(strlen(host) + strlen(user_home) + 15); // Allocate space for the full file path
148 |
149 | strncpy(file_path,user_home,strlen(user_home)); // Copy the home directory path in
150 | strncat(file_path,"/.",2); // Concatenate a /. to ensure full path
151 | strncat(file_path,host,strlen(host)); // Add the hostname
152 | strncat(file_path,".priv",strlen(".priv")); // Add a .priv extension
153 |
154 | if((key_file = fopen(file_path,"r")) == NULL) { // If opening fails
155 | w_free(file_path); // free the memory we used
156 | return -1; // we dont have the file, return -1
157 | }
158 | else { // Otherwise
159 | fclose(key_file); // close the now open file
160 | w_free(file_path); // free the memory we used
161 | return 0; // and return success
162 | }
163 | }
164 |
165 | RSA *getServerKey(const char *host, const char *username) {
166 | char *file_path = NULL; // Buffer where we will build the path
167 | const char *user_home = NULL; // The user's home directory
168 | RSA *my_key = NULL;
169 |
170 | if((user_home = getUsersHome(username)) == NULL) {
171 | report_error_q("Unable to find user's home directory",__FILE__,__LINE__,0);
172 | }
173 |
174 | file_path = (char *)w_malloc(strlen(host) + strlen(user_home) + 15); // Allocate space for the full file path
175 |
176 | strncpy(file_path,user_home,strlen(user_home)); // Copy the home directory path in
177 | strncat(file_path,"/.",2); // Concatenate a /. to ensure full path
178 | strncat(file_path,host,strlen(host)); // Add the hostname
179 | strncat(file_path,".priv",strlen(".priv")); // Add a .priv extension
180 | my_key = key_read_priv(file_path); // read the key in
181 | w_free(file_path);
182 | return my_key;
183 | }
184 |
185 | /**
186 | * Write the private portion of an RSA key to the file .[host].priv.
187 | */
188 | void writePrivKey(const char *host, const char *username, RSA *my_key) {
189 | char *file_path = NULL; // Buffer where we will build the path
190 | const char *user_home = NULL; // The user's home directory
191 |
192 | if((user_home = getUsersHome(username)) == NULL) {
193 | report_error_q("Unable to find user's home directory",__FILE__,__LINE__,0);
194 | }
195 |
196 | file_path = (char *)w_malloc(strlen(host) + strlen(user_home) + 15); // Allocate space for the full file path
197 |
198 | strncpy(file_path,user_home,strlen(user_home)); // Copy the home directory path in
199 | strncat(file_path,"/.",2); // Concatenate a /. to ensure full path
200 | strncat(file_path,host,strlen(host)); // Add the hostname
201 | strncat(file_path,".priv",strlen(".priv")); // Add a .priv extension
202 |
203 | if(key_write_priv(my_key,file_path) != 0) { // Write the key
204 | report_error_q("Unable to write private key to file",__FILE__,__LINE__,0);
205 | }
206 | }
207 |
208 | /**
209 | * Prompt the user for a password and return it in a static buffer that will be overwritten with subsequent calls
210 | */
211 | const char *getUserPassword(void) {
212 | struct termios terminal_setup, old_terminal_setup;
213 | static char *password_buffer[2048];
214 | char *newline = NULL;
215 |
216 | memset(password_buffer,'\0',2048);
217 |
218 | tcgetattr(STDIN_FILENO, &terminal_setup); // Retrieve the current terminal settings
219 | old_terminal_setup = terminal_setup; // Save the current setup so we don't clobber it
220 |
221 | terminal_setup.c_lflag &= ~ECHO; // Turn echoing flag off
222 | terminal_setup.c_lflag |= ECHONL;
223 | tcsetattr(STDIN_FILENO, TCSAFLUSH, &terminal_setup); // Apply the changed settings
224 |
225 | printf("Password: "); // Prompt for the password
226 | fgets((char *)password_buffer, 2048, stdin); // Read the password
227 | tcsetattr(STDIN_FILENO, TCSANOW, &old_terminal_setup); // Reset the old attributes
228 |
229 | // We need to truncate the last \n that may have been inserted by fgets
230 | while((newline = strstr((char *)password_buffer,"\n")) != NULL) {
231 | *newline = '\0';
232 | }
233 |
234 | return (char *)password_buffer;
235 | }
236 |
237 |
238 | int main(int argc, char *argv[]) {
239 | SSL *ssl_connection = NULL; // Pointer for our SSL connection
240 | const char *host = NULL, *port = NULL; // Pointers to the hostname and port number on the cmd line
241 | const char *username = NULL; // Username store
242 | char *response = NULL; // Server responses
243 | char *signed_data_buffer = NULL; // Buffer and count for our signed data
244 | unsigned int signed_data_buffer_size = 0;
245 | RSA *my_rsa_key = NULL; // Our RSA key
246 |
247 | if(argc != 3) {
248 | fprintf(stderr, "Usage: %s host port\n",argv[0]); // We should report the problem in a nicer way than report_error
249 | exit(EXIT_FAILURE); // Exit with an error
250 | }
251 |
252 | //signal(SIG_PIP,SIG_IGN);
253 |
254 | w_memory_init(); // Initialize our memory wrappers state
255 | openssl_init(); // Initialize the OpenSSL library
256 |
257 | host = argv[1]; // Hostname is the first argument
258 | port = argv[2]; // Port is the second argument
259 | username = getUsername(); // Get our username
260 |
261 | if(username == NULL) {
262 | report_error_q("Unable to determine the username of this process.",__FILE__,__LINE__,0);
263 | }
264 |
265 | if((ssl_connection = ssl_client_connect(host,port)) == NULL) { // Attempt a connection using our wrapper
266 | report_error_q(ERR_error_string(ERR_get_error(),NULL),__FILE__,__LINE__,0); // Report any problems and quit
267 | }
268 |
269 | if(haveServerKey(host,username) == 0) { // First we look to see whether we have a key already
270 | ssl_write_uint(ssl_connection,REQUEST_KEY_AUTH); // Tell the server we want to use PKI authentication
271 | ssl_write_string(ssl_connection,username); // Then we send the username
272 |
273 | my_rsa_key = getServerKey(host,username);
274 | if(my_rsa_key == NULL) { // Validate the key that was read in
275 | report_error_q("Key file exists, but data is invalid",__FILE__,__LINE__,0);
276 | }
277 |
278 | signed_data_buffer = (char *)w_malloc(key_buffer_size(my_rsa_key)); // Allocate memory for the signed data and then sign it
279 | signed_data_buffer_size = key_sign_data(my_rsa_key,username,strlen(username),signed_data_buffer,key_buffer_size(my_rsa_key));
280 | ssl_write_uint(ssl_connection,signed_data_buffer_size); // Tell the server how much data to expect
281 | ssl_write_bytes(ssl_connection,signed_data_buffer,signed_data_buffer_size); // And send the data
282 |
283 | if(ssl_read_uint(ssl_connection) == SERVER_AUTH_SUCCESS) {
284 | printf("Server responded with SERVER_AUTH_SUCCESS\n");
285 | } else {
286 | printf("Server responded with SERVER_AUTH_FAILURE\n");
287 | }
288 | w_free(response);
289 | } else { // We dont have a PKI key, so we will do password authentication
290 | ssl_write_uint(ssl_connection,REQUEST_PASS_AUTH); // Tell the server we want to do password authentication
291 | ssl_write_string(ssl_connection,username); // Send the username
292 | ssl_write_string(ssl_connection,getUserPassword()); // Send the user's password attempt
293 |
294 | if(ssl_read_uint(ssl_connection) == SERVER_AUTH_SUCCESS) {
295 | printf("Server responded with SERVER_AUTH_SUCCESS, setting up a PKI key for the future.\n");
296 | my_rsa_key = key_create_key(); // Create a new RSA key
297 | if(!my_rsa_key) { // Verify it was actually created
298 | report_error("Error creating RSA key.",__FILE__,__LINE__,0);
299 | }
300 | key_net_write_pub(my_rsa_key,ssl_connection); // Send the public portion of the key to the server
301 | writePrivKey(host,username,my_rsa_key); // Write the private portion to a file
302 | } else {
303 | printf("Server responded with SERVER_AUTH_FAILURE\n");
304 | }
305 | }
306 |
307 | SSL_shutdown(ssl_connection);
308 | SSL_free(ssl_connection);
309 | return 0;
310 | }
311 |
312 |
313 |
--------------------------------------------------------------------------------
/Chapter13/client/auth_client.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Authentication Client - For testing of the Authentication Server
3 | * By Nathan Yocom, 2004 - For APress Book "The Definitive Guide to Linux Network Programming"
4 | *
5 | * auth_client.h = Maine client header file
6 | */
7 |
8 | #ifndef AUTH_CLIENT_H
9 | #define AUTH_CLIENT_H
10 |
11 | #include // Included to prevent echoing of password
12 |
13 | // Connect via TLSv1 to the given host on the given port
14 | SSL * ssl_client_connect(const char *host, const char *port);
15 | // Get the current users username
16 | const char *getUsername(void);
17 | // Get the given users home directory path
18 | const char *getUsersHome(const char *username);
19 | // Check the users home directory for an existing host key file
20 | int haveServerKey(const char *host,const char *username);
21 | // Get a users key
22 | RSA *getServerKey(const char *host,const char *username);
23 | // Write the given private key to the users home directory
24 | void writePrivKey(const char *host, const char *username, RSA *my_key);
25 | // Prompt the user for their password
26 | const char *getUserPassword(void);
27 |
28 | #endif
29 |
--------------------------------------------------------------------------------
/Chapter13/common/Makefile:
--------------------------------------------------------------------------------
1 | CC = gcc -Wall
2 |
3 | INCLUDES = -I./
4 |
5 | CFLAGS += $(INCLUDES)
6 |
7 | all: common.o
8 |
9 | common.o: common.c common.h
10 | $(CC) -c $(CFLAGS) common.c
11 |
12 | clean:
13 | rm -f common.o
14 |
15 |
--------------------------------------------------------------------------------
/Chapter13/common/common.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Common Code for Authentication Client and Server
3 | * By Nathan Yocom, 2004 - For APress Book "The Definitive Guide to Linux Network Programming"
4 | */
5 | #include "common.h"
6 |
7 | /**
8 | * Reports the error specified in msg to stderr, indicates the name of the file and line number the
9 | * error occured at as well.
10 | *
11 | * @param msg The string to print as the message
12 | * @param file The name of the file, typically passed as __FILE__
13 | * @param line_no The line number within the file parameter, typically passed as __LINE__
14 | * @param use_perror Flag indicating whether the system call perror() should be used to report the error (non-zero), or not (zero)
15 | */
16 | void report_error(const char *msg, const char *file, int line_no, int use_perror)
17 | {
18 | fprintf(stderr,"[%s:%d] ",file,line_no); // Print the file and line
19 |
20 | if(use_perror != 0) {
21 | perror(msg); // Use perror
22 | } else { // otherwise
23 | fprintf(stderr, "%s\n",msg); // Print the message
24 | }
25 | }
26 |
27 | /**
28 | * Reports the error specified in msg to stderr, indicates the name of the file and line number the
29 | * error occured at as well, exactly as in report_error(), and calls exit() when finished.
30 | *
31 | * @param msg The string to print as the message
32 | * @param file The name of the file, typically passed as __FILE__
33 | * @param line_no The line number within the file parameter, typically passed as __LINE__
34 | * @param use_perror Flag indicating whether the system call perror() should be used to report the error (non-zero), or not (zero)
35 | *
36 | * @return Does not return
37 | */
38 | void report_error_q(const char *msg, const char *file, int line_no, int use_perror)
39 | {
40 | report_error(msg,file,line_no,use_perror);
41 | exit(EXIT_FAILURE);
42 | }
43 |
44 | /**
45 | * Wraps the malloc() function so that we can keep track of where and how much memory we have allocated. This
46 | * allows us to catch out of memory errors, as well as potentially monitor and report potential leaks.
47 | *
48 | * @param bytes The number of bytes needed to be allocated
49 | *
50 | * @return If successful the return value is the start address of the newly allocated memory, otherwise the function
51 | * does not return.
52 | */
53 | void * w_malloc(size_t bytes) {
54 | void *memory = NULL; // Store the allocated memory here
55 | memory_list *new_item = NULL; // Our new item structure
56 | memory = calloc(bytes,1); // Try to allocate the memory
57 | new_item = calloc(1,sizeof(struct memory_list)); // Then allocate memory for the list item as well
58 | if(memory) { // Make sure the first allocation worked
59 | if(new_item == NULL) { // Make sure the second allocation worked
60 | report_error_q("Memory allocation error, no room for memory list item.",__FILE__,__LINE__,0);
61 | }
62 | global_memory_count += bytes + sizeof(struct memory_list); // Increment our global byte count
63 | new_item->address = memory; // Initialize the new item's address pointer
64 | new_item->size = bytes; // Set the bytes parameter to the size of the buffer in ->address
65 | new_item->next = NULL; // Start with a NULL prev and next pointer
66 | new_item->prev = NULL;
67 | if(memory_list_head) { // If the list already has items
68 | new_item->next = memory_list_head; // Then we just add this item to the head of the list
69 | memory_list_head->prev = new_item;
70 | memory_list_head = new_item;
71 | } else {
72 | memory_list_head = new_item; // The list didn't have items, we add this as the head
73 | }
74 | return memory; // Return the allocated memory
75 | } else {
76 | report_error_q("Memory allocation error, out of memory.",__FILE__,__LINE__,0); // The first allocation failed
77 | return NULL; // We don't actually get here, but the compiler will complain otherwise
78 | }
79 | }
80 |
81 | /**
82 | * Wraps the malloc() function so that we can keep track of where and how much memory we have allocated. This
83 | * allows us to catch out of memory errors, as well as potentially monitor and report potential leaks.
84 | *
85 | * @param bytes The number of bytes needed to be allocated
86 | *
87 | * @return If successful nothing is returned, if something fails this function will not return and will report an error
88 | * to stderr.
89 | */
90 | void w_free(void *f_address) {
91 | memory_list *temp = NULL,*found = NULL; // Temporary pointers for list manipulation
92 |
93 | if(f_address == NULL) // Can't free nothing ;)
94 | return;
95 |
96 | for(temp=memory_list_head;temp!=NULL;temp = temp->next) { // Walk the memory list looking for an item
97 | if(temp->address == f_address) { // with the same address as we are asked to free
98 | found = temp; // and note that we have found it then
99 | break; // break from the for loop to save time
100 | }
101 | }
102 |
103 | if(!found) { // If we haven't found it, then we shouldn't free it
104 | report_error_q("Unable to free memory not previously allocated",__FILE__,__LINE__,0); // Report this as an error
105 | }
106 |
107 | global_memory_count -= found->size + sizeof(struct memory_list); // Decrement our global byte count
108 |
109 | free(f_address); // Actually free the data
110 | // Then remove the item from the list:
111 | if(found->prev) // If there is an item previous to us
112 | found->prev->next = found->next; // point it at the next item
113 | if(found->next) // If there is an item after us
114 | found->next->prev = found->prev; // point it at the previous item
115 | if(found == memory_list_head) // If we are the head of the list
116 | memory_list_head = found->next; // move the head of the list up one
117 |
118 | free(found); // Now we can actually free the memory used by our item
119 | }
120 |
121 | /**
122 | * Wrapper that allows us to free all allocated memory at exit time
123 | */
124 | void w_free_all(void) {
125 | memory_list *temp = NULL;
126 |
127 | while(memory_list_head) {
128 | free(memory_list_head->address);
129 | temp = memory_list_head->next;
130 | free(memory_list_head);
131 | memory_list_head = temp;
132 | }
133 | }
134 |
135 | /**
136 | * This initialization function should be called only once (although it tries to prevent double calling errors) to
137 | * initialize the global variables used for memory management/wrappers. This includes setting the count of allocated
138 | * memory to 0 and the head of the list to NULL.
139 | */
140 | void w_memory_init(void) {
141 | static int state = 0; // Initialize a static variable we can use to keep state
142 |
143 | if(state != 0) // If the variable is not zero then we have already been called
144 | return; // do nothing but return
145 | // If the variable is 0 then we have not been called before
146 | state = 1; // Note that we have now been called
147 | memory_list_head = NULL; // Set the head of the memory list to NULL (no items)
148 | global_memory_count = 0; // Start the memory allocation count at 0
149 | atexit(w_free_all); // Register to have w_free_all() called at normal termination
150 | }
151 |
152 | /**
153 | * This initialization function should be called only once (although it tries to prevent double calling errors) to
154 | * initialize the OpenSSL libraries and seed the PRNG with data from /dev/random.
155 | */
156 | void openssl_init(void) {
157 | static int state = 0; // Initialize a static variable we can use to keep state
158 | int bytes_read = 0;
159 |
160 | if(state != 0) // If the variable is not zero then we have already been called
161 | return; // do nothing but return
162 | // If the variable is 0 then we have not been called before
163 | state = 1; // Note that we have now been called
164 | if(atexit(openssl_destroy)) // Register to have openssl_destroy automagically called on exit
165 | report_error("atexit() failed, openssl_destroy() will not be called on exit.",
166 | __FILE__,__LINE__,0); // Report (non-fatal) that this didn't work
167 | OpenSSL_add_all_algorithms(); // Initialize OpenSSL ciphers and digests
168 | SSL_load_error_strings(); // Load all available error strings for later use
169 |
170 | // Try to seed the PRNG with ENTROPY_SIZE bytes from /dev/random
171 | printf("Seeding PRNG with /dev/random, this may take a moment... ");
172 | fflush(stdout); // Make sure our message displays (not buffers)
173 | if((bytes_read = RAND_load_file("/dev/random",ENTROPY_SIZE)) != ENTROPY_SIZE) {
174 | report_error_q("Seeding PRNG failed",__FILE__,__LINE__,0);
175 | }
176 | // If we get here, we are all done
177 | printf("Done\n");
178 | fflush(stdout);
179 | }
180 |
181 | /**
182 | * This function is registered to be called on normal program termination with the atexit() system call. When
183 | * the program terminates, whether by return or by a call to exit(), this function will be called and will then
184 | * cleanup OpenSSL memory usage resulting from the openssl_init function.
185 | */
186 | void openssl_destroy(void) {
187 | EVP_cleanup(); // Cleanup from the OpenSSL_add_all_algorithms()
188 | ERR_free_strings(); // Cleanup from the SSL_load_error_strings()
189 | }
190 |
191 |
192 | /**
193 | * Reads a string into a buffer of length limit that is created with w_malloc.
194 | * Strings longer than 'limit' characters will be terminated and subsequent
195 | * calls will read the remainder of the string. If an error occurs
196 | * the string as it stands is returned. If no error occurs, the resulting string is returned.
197 | * Calling functions should take care to ensure they use w_free() to release
198 | * the string returned.
199 | *
200 | * @param my_ssl The SSL session to read from
201 | * @param limit The maximum number of bytes to read before returning
202 | * @return A NULL terminated string created with w_malloc(), the string may be truncated or empty on error
203 | */
204 | char *ssl_read_string(SSL *my_ssl,size_t limit)
205 | {
206 | char * buffer = NULL; // The buffer to store the string in
207 | char this_one; // The last read byte
208 | int error = 0, read_in = 0; // Counters for our read loop
209 |
210 | buffer = w_malloc(limit); // Allocate space for the string read in
211 |
212 | while(read_in < limit) { // Ensure we don't overflow
213 | error = SSL_read(my_ssl,&this_one,1); // Read a single byte from SSL, this doesn't seem
214 | // very optimized, but SSL does a lot of internal buffering
215 | // that prevents this from being an overly large sacrifice
216 | if(error > 0) { // As long as we read some data
217 | buffer[read_in++] = this_one; // Insert that data into our string
218 | if(this_one == '\0') return buffer; // Check to see if it was null, and if so, return the string as it stands
219 | } else { // SSL_read returned an error
220 | return buffer; // Return whatever we have read up to this point
221 | }
222 | }
223 | // If we get here, then we did not encounter an \0 character
224 | // before reaching the limit of our buffer.
225 | buffer[limit-1]='\0'; // Terminate the string and truncate
226 | return buffer; // and return the resulting string
227 | }
228 |
229 | /**
230 | * Write a NULL terminated string over an SSL connection. If an error occurs writing simply stops and this function
231 | * returns.
232 | * @param my_ssl The ssl connection to use
233 | * @param message The message to write
234 | */
235 | void ssl_write_string(SSL *my_ssl,const char *message)
236 | {
237 | int ret_val = 0, bytes_written = 0; // Counters and state management for the write loop
238 | int bytes_to_write; // Counter to keep track of where we are in the message
239 |
240 | bytes_to_write = strlen(message) + 1; // We start by needing the send the whole message
241 |
242 | while(bytes_written < bytes_to_write) { // While there are bytes to write
243 | ret_val = SSL_write(my_ssl, message + bytes_written, bytes_to_write - bytes_written); // Write as many as we can
244 | if(ret_val <= 0) {
245 | break; // Break out of our loop if an error (i.e. SSL_SHUTDOWN) occurs
246 | } else {
247 | bytes_written += ret_val; // Otherwise increment our count by the number of bytes written so we
248 | // can loop and send the rest in subsequent iterations
249 | }
250 | }
251 | }
252 |
253 | /**
254 | * Read an unsigned int from the SSL connection given. We use the ntohl()
255 | * function to ensure proper endianess
256 | *
257 | * @param my_ssl The SSL connection to read from
258 | * @return An unsigned integer value, this value is 0 on error
259 | */
260 | unsigned int ssl_read_uint(SSL *my_ssl)
261 | {
262 | unsigned int value = 0; // Our default return is 0 for error
263 |
264 | if(ssl_read_bytes(my_ssl,&value,sizeof(unsigned int)) != -1) { // If reading was successful
265 | value = ntohl(value); // Ensure proper endianess
266 | return value; // and return the value
267 | } else
268 | return 0; // If we had an error, return 0
269 | }
270 |
271 | /**
272 | * Write an unsigned int to the given SSL connection, we use htonl to ensure
273 | * proper endianess.
274 | */
275 | void ssl_write_uint(SSL *my_ssl,unsigned int value)
276 | {
277 | unsigned int to_write = 0; // The buffer we will actually write
278 | to_write = htonl(value); // Assign the buffer the network byte order ver of value
279 | ssl_write_bytes(my_ssl,&to_write,sizeof(unsigned int)); // Write the buffer
280 | }
281 |
282 | /**
283 | * Read a single byte from the SSL connection.
284 | *
285 | * @param my_ssl The SSL connection to read from
286 | * @return The byte read
287 | */
288 | byte_t ssl_read_byte(SSL *my_ssl)
289 | {
290 | byte_t this_byte;
291 | if(SSL_read(my_ssl,&this_byte,sizeof(byte_t)) != 1) // Try to read a single byte
292 | return '\0'; // Return NULL on error
293 | else {
294 | return this_byte;
295 | }
296 |
297 | }
298 |
299 | /**
300 | * Read a stream of bytes from an SSL connection.
301 | *
302 | * @param my_ssl The ssl connection to use
303 | * @param buf The buffer to read into
304 | * @param limit The number of bytes to read
305 | *
306 | * @return 0 on success, -1 on error
307 | */
308 | int ssl_read_bytes(SSL *my_ssl,void *buf,unsigned int limit)
309 | {
310 | byte_t *my_buf = NULL; // Pointer to the buffer we want to write to
311 | unsigned int x = 0; // Counter for iteration over the buffer
312 |
313 | my_buf = (byte_t *)buf; // Point our pointer at the buffer provided in the arg list
314 |
315 | for(;x // Needed for size_t
10 | #include // Needed for fprintf and stderr
11 | #include // For strlen etc
12 |
13 | #include // OpenSSL header files for openssl_init
14 | #include
15 | #include
16 | #include
17 |
18 | #include // Includes for the network function
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | #include
25 |
26 | #include // Include for getpwent
27 |
28 |
29 | #define ENTROPY_SIZE 512 // Define a constant for controlling how many bytes to seed PRNG with
30 |
31 | #define byte_t char // Define a constant to be used for a single byte data type, if sizeof(char) > 1 on your system, this should
32 | // be changed to something that is sizeof(??) == 1
33 |
34 | #define REQUEST_KEY_AUTH 10 // Client message tells the server to go into Key authentication mode
35 | #define REQUEST_PASS_AUTH 11 // Client message tells the server to go into Password auth mode
36 | #define SERVER_AUTH_SUCCESS 1 // Server message tells the client that authentication was successful
37 | #define SERVER_AUTH_FAILURE 2 // Server message tells the client that authentication failed
38 | #define SSL_ERROR 0 // If ssl_read_uint returns 0 it is an error
39 |
40 | // Report an error, then exit the thread/program
41 | void report_error_q(const char *msg, const char *file, int line_no, int use_perror);
42 | // Report an error without exiting
43 | void report_error(const char *msg, const char *file, int line_no, int use_perror);
44 |
45 |
46 | // The structure we use to maintain a list of allocated memory
47 | typedef struct memory_list {
48 | void *address;
49 | size_t size;
50 | struct memory_list *next;
51 | struct memory_list *prev;
52 | } memory_list;
53 |
54 | // Memory management wrappers for leak detection
55 | void *w_malloc(size_t bytes);
56 | void w_free(void *f_address);
57 | void w_free_all(void);
58 |
59 | // The global memory allocation list used by the memory management wrappers
60 | memory_list *memory_list_head;
61 | // The global couter indicating the number of bytes allocated
62 | unsigned long global_memory_count;
63 |
64 | // A one-time initialization function to setup the memory list and global memory count variables
65 | void w_memory_init(void);
66 |
67 | // A one-time initializeation function to setup and initialize OpenSSL, including seeding the PRNG
68 | void openssl_init(void);
69 |
70 | // A function that is registered to be called when the program terminates successfully, this cleans
71 | // up memory used by openssl_init automagically
72 | void openssl_destroy(void);
73 |
74 | // SSL Management wrapper allows us to read a null terminated string
75 | char *ssl_read_string(SSL *my_ssl,size_t limit);
76 | // SSL Management wrapper allows us to write a null terminated string
77 | void ssl_write_string(SSL *my_ssl,const char *message);
78 | // SSL Management wrapper allows us to read an unsigned int
79 | unsigned int ssl_read_uint(SSL *my_ssl);
80 | // SSL Management wrapper allows us to write an unsigned int
81 | void ssl_write_uint(SSL *my_ssl,unsigned int value);
82 | // SSL Management wrapper allows us to read a single byte
83 | byte_t ssl_read_byte(SSL *my_ssl);
84 | // SSL Management wrapper allows us to read a stream of bytes
85 | int ssl_read_bytes(SSL *my_ssl,void *buf,unsigned int limit);
86 | // SSL Management wrapper allows us to write a single byte
87 | void ssl_write_byte(SSL *my_ssl,byte_t this_byte);
88 | // SSL Management wrapper allows us to write a stream of bytes
89 | void ssl_write_bytes(SSL *my_ssl, void *message, unsigned int length);
90 |
91 | // A Network management wrapper allows us to get the IP address of a client
92 | const char *network_get_ip_address(SSL *my_ssl);
93 |
94 | // Create a new RSA Key
95 | RSA * key_create_key(void);
96 | // Destroy a key in memory
97 | void key_destroy_key(RSA *);
98 | // Determine maximum signed data buffer size
99 | unsigned int key_buffer_size(RSA *);
100 | // Sign data
101 | unsigned int key_sign_data(RSA *,const char *,unsigned int,char *,unsigned int);
102 | // Write a private key to a file
103 | int key_write_priv(RSA*, char *);
104 | // Read a private key from a file
105 | RSA *key_read_priv(char *);
106 | // Write a public key over the network
107 | void key_net_write_pub(RSA *,SSL *);
108 | // Verify private key with public key
109 | int key_verify_signature(RSA *, char *,unsigned int,char *,unsigned int);
110 | // Write a public key to a file
111 | int key_write_pub(RSA*, char *);
112 | // Read public key from the network
113 | RSA *key_net_read_pub(SSL *);
114 | // Read a public key from a file
115 | RSA *key_read_pub(char *);
116 |
117 | #endif
118 |
--------------------------------------------------------------------------------
/Chapter13/server/Makefile:
--------------------------------------------------------------------------------
1 | CC = gcc -Wall
2 | COMMONDIR = ../common
3 | COMMONLIB = $(COMMONDIR)/common.o
4 |
5 | INCLUDES = -I$(COMMONDIR) -I./
6 |
7 | LIBS = $(COMMONLIB)
8 | LIBS += -lcrypto -lssl -lpam
9 |
10 | CFLAGS += $(INCLUDES)
11 |
12 | .c.o:
13 | $(CC) $(CFLAGS) $(INCLUDES) -c $<
14 |
15 | BINS = auth_server
16 |
17 | all: libs $(BINS)
18 |
19 | libs:
20 | make -C $(COMMONDIR)
21 |
22 | auth_server.o: auth_server.c auth_server.h $(COMMONLIB)
23 | $(CC) -c $(CFLAGS) auth_server.c
24 |
25 | auth_server: auth_server.o
26 | $(CC) -o auth_server auth_server.o $(LIBS)
27 |
28 | clean:
29 | rm -f *.o
30 | rm -f $(BINS)
31 | make -C $(COMMONDIR) clean
32 |
33 |
--------------------------------------------------------------------------------
/Chapter13/server/auth_server.c:
--------------------------------------------------------------------------------
1 | /**
2 | * Authentication Server - For testing of the Authentication Server
3 | * By Nathan Yocom, 2004 - For APress Book "The Definitive Guide to Linux Network Programming"
4 | *
5 | * auth_server.c = Main server source
6 | */
7 |
8 | #include "common.h"
9 | #include "auth_server.h"
10 |
11 | /**
12 | * Authenticate a given username and password against the systems PAM interface.
13 | * Null username and/or passwords will fail. The pam service name in the cache
14 | * as pam_service will be used if it exists, otherwise this will default to 'login'.
15 | *
16 | * @param username The username to authenticate
17 | * @param password The password to authenticate
18 | * @return An integer value indicating success or failure, -1 is fail, 1 is success
19 | */
20 | int pam_authenticate_user(const char *username,const char *password)
21 | {
22 | struct auth_struct buffer; // Setup our custom structure to provide data through PAM
23 | static struct pam_conv myauthconv = { // Setup the structure that will tell PAM about our Conversation func
24 | auth_conv,
25 | NULL
26 | };
27 | pam_handle_t *pamh=NULL; // Our handle into PAM
28 | int ret = 0, authenticated = 0; // Some status holders
29 |
30 | buffer.username = username; // Save a pointer to our username
31 | buffer.password = password; // and password
32 | myauthconv.appdata_ptr = &buffer; // Set the pointer to our structure, this way its available in the
33 | // callback process
34 |
35 | if(username && password) // Don't call into PAM if one or the other isn't set
36 | {
37 | authenticated =
38 | (ret = pam_start("login", NULL, &myauthconv, &pamh)) == PAM_SUCCESS && // Connect with PAM on the "login" service
39 | (ret = pam_authenticate(pamh, 0)) == PAM_SUCCESS && // Ensure that the account authenticates
40 | (ret = pam_acct_mgmt(pamh, 0)) == PAM_SUCCESS; // And that it is not expired or disabled
41 |
42 | pam_end(pamh,ret); // End our connection with PAM
43 | }
44 |
45 | if(authenticated) // Return the result
46 | return 1; // Authenticated
47 | else
48 | return -1; // Not
49 | }
50 |
51 | /**
52 | * PAM Conversation function. This is the callback entry for PAM to get the username
53 | * and password to authenticate.
54 | */
55 | int auth_conv(int num_msg,const struct pam_message **msg, struct pam_response **response, void *appdata_ptr)
56 | {
57 | struct pam_response *reply_with = NULL; // We must set this up to pass back to PAM
58 | int num_replies;
59 | struct auth_struct *user_data;
60 | user_data = (struct auth_struct *) appdata_ptr; // This is our data, with username/password
61 |
62 | if(num_msg <= 0)
63 | return PAM_CONV_ERR;
64 |
65 | reply_with = (struct pam_response *)calloc(num_msg, sizeof(struct pam_response));
66 |
67 | if(reply_with == NULL)
68 | return PAM_SYSTEM_ERR;
69 |
70 | for(num_replies = 0; num_replies < num_msg; num_replies++)
71 | {
72 | if(msg[num_replies]->msg_style == PAM_PROMPT_ECHO_OFF)
73 | {
74 | reply_with[num_replies].resp_retcode = PAM_SUCCESS;
75 | reply_with[num_replies].resp = strdup(user_data->password); // Copy the password in
76 | }
77 | else if(msg[num_replies]->msg_style == PAM_PROMPT_ECHO_ON)
78 | {
79 | reply_with[num_replies].resp_retcode = PAM_SUCCESS;
80 | reply_with[num_replies].resp = strdup(user_data->username); // Copy the username in
81 | }
82 | else
83 | {
84 | free(reply_with);
85 | return PAM_CONV_ERR;
86 | }
87 | }
88 |
89 | *response = reply_with;
90 | return PAM_SUCCESS; // Tell PAM we are done
91 | }
92 |
93 | /** The first time this function is called it sets up a listening BIO
94 | * on the given port. Every following call returns the next incoming
95 | * connectin, or blocks until one is available. When called with a NULL
96 | * argument the listening BIO is closed and resources freed.
97 | */
98 | SSL *get_connection(char *port) {
99 | SSL *my_ssl = NULL; // The next connection
100 | static SSL_CTX *my_ssl_ctx = NULL; // We use static here so we can use them on subsequent calls
101 | static SSL_METHOD *my_ssl_method = NULL;
102 | static BIO *server_bio = NULL;
103 | BIO *client_bio = NULL;
104 |
105 | if (port && !server_bio) { // If the port is set, but we dont have a BIO
106 | my_ssl_method = TLSv1_server_method(); // then we need to setup a new connection
107 |
108 | if ((my_ssl_ctx = SSL_CTX_new(my_ssl_method)) == NULL) { // Setup a context
109 | report_error_q("Unable to setup context.",__FILE__,__LINE__,0);
110 | }
111 |
112 | // We assume our certificate is called server.pem and is in the current dir
113 | SSL_CTX_use_certificate_file(my_ssl_ctx,"server.pem",SSL_FILETYPE_PEM);
114 | // We assume our private key is called server.pem and is in the current dir
115 | SSL_CTX_use_PrivateKey_file(my_ssl_ctx,"server.pem",SSL_FILETYPE_PEM);
116 |
117 | if (!SSL_CTX_check_private_key(my_ssl_ctx)) { // Verify the certificate
118 | report_error_q("Private key does not match certificate",__FILE__,__LINE__,0);
119 | }
120 |
121 | // Setup for accepting and get our BIO
122 | if ((server_bio = BIO_new_accept(port)) == NULL) {
123 | report_error_q(ERR_error_string(ERR_get_error(),NULL),__FILE__,__LINE__,0); // Report any problems and quit
124 | }
125 |
126 | // Make sure the BIO is setup and in a state to get incoming connectins
127 | if (BIO_do_accept(server_bio) <= 0) {
128 | report_error_q(ERR_error_string(ERR_get_error(),NULL),__FILE__,__LINE__,0); // Report any problems and quit
129 | }
130 | }
131 |
132 | if (port == NULL) { // If the port is NOT set, we should close things down
133 | SSL_CTX_free(my_ssl_ctx);
134 | BIO_free(server_bio);
135 | } else { // Otherwise we are already to accept new connections, just get the next one
136 | if (BIO_do_accept(server_bio) <= 0) { // Get the next connection
137 | report_error_q(ERR_error_string(ERR_get_error(),NULL),__FILE__,__LINE__,0); // Report any problems and quit
138 | }
139 |
140 | client_bio = BIO_pop(server_bio); // Pop it off the stack
141 | if ((my_ssl = SSL_new(my_ssl_ctx)) == NULL) { // Setup a new SSL pointer for it
142 | report_error_q(ERR_error_string(ERR_get_error(),NULL),__FILE__,__LINE__,0); // Report any problems and quit
143 | }
144 |
145 | SSL_set_bio(my_ssl,client_bio,client_bio); // Set the bio from the stack as the read and write pipes
146 |
147 | if (SSL_accept(my_ssl) <= 0) { // Negotiate a connection with the client
148 | report_error_q(ERR_error_string(ERR_get_error(),NULL),__FILE__,__LINE__,0); // Report any problems and quit
149 | }
150 | }
151 |
152 | return my_ssl; // This will be the next connection, or NULL depending on
153 | // how we were called
154 | }
155 |
156 | /**
157 | * This is called as the starting point for each new process, once we are here we have
158 | * a connection, and we just need to exit() with EXIT_SUCCESS when we are done.
159 | */
160 | void child_process(SSL *my_ssl) {
161 | char *username = NULL, *password = NULL,*key_file = NULL;
162 | RSA *users_key = NULL;
163 | int authenticated = 0;
164 | int string_size = 0;
165 | unsigned int signed_size = 0;
166 | byte_t *signed_buffer = NULL;
167 | w_memory_init(); // We need to initialize our memory allocation routines
168 |
169 |
170 | switch (ssl_read_uint(my_ssl)) {
171 | case SSL_ERROR:
172 | report_error_q(ERR_error_string(ERR_get_error(),NULL),__FILE__,__LINE__,0); // Report any problems and quit
173 | break;
174 | case REQUEST_KEY_AUTH:
175 | // Key Authentication
176 | username = ssl_read_string(my_ssl,1024);
177 | string_size = strlen(username) + strlen(network_get_ip_address(my_ssl)) + 10;
178 | key_file = w_malloc(string_size);
179 | snprintf(key_file,string_size,"%s.%s.pub",username,network_get_ip_address(my_ssl));
180 | users_key = key_read_pub(key_file);
181 | w_free(key_file);
182 | signed_size = ssl_read_uint(my_ssl);
183 | signed_buffer = (byte_t *)w_malloc(signed_size);
184 | if(ssl_read_bytes(my_ssl,signed_buffer,signed_size) != 0)
185 | report_error_q("Error reading signed data from client",__FILE__,__LINE__,0);
186 |
187 | if(key_verify_signature(users_key,signed_buffer,signed_size,username,strlen(username)) == 0) {
188 | ssl_write_uint(my_ssl,SERVER_AUTH_SUCCESS);
189 | printf("(%s) User %s authenticated via PKI\n",network_get_ip_address(my_ssl),username);
190 | } else {
191 | ssl_write_uint(my_ssl,SERVER_AUTH_FAILURE);
192 | printf("(%s) User %s failed via PKI\n",network_get_ip_address(my_ssl),username);
193 | }
194 | break;
195 | case REQUEST_PASS_AUTH:
196 | // Password authentication
197 | username = ssl_read_string(my_ssl,1024);
198 | password = ssl_read_string(my_ssl,1024);
199 | authenticated = pam_authenticate_user(username,password);
200 | printf("(%s) User %s %s via PAM\n",network_get_ip_address(my_ssl),username,authenticated ? "authenticated" : "failed");
201 | if(authenticated) {
202 | ssl_write_uint(my_ssl,SERVER_AUTH_SUCCESS);
203 | users_key = key_net_read_pub(my_ssl);
204 | string_size = strlen(username) + strlen(network_get_ip_address(my_ssl)) + 10;
205 | key_file = w_malloc(string_size);
206 | snprintf(key_file,string_size,"%s.%s.pub",username,network_get_ip_address(my_ssl));
207 | key_write_pub(users_key,key_file);
208 | w_free(key_file);
209 | } else {
210 | ssl_write_uint(my_ssl,SERVER_AUTH_FAILURE);
211 | }
212 | break;
213 | }
214 |
215 | if(users_key) {
216 | key_destroy_key(users_key);
217 | }
218 |
219 | SSL_shutdown(my_ssl);
220 | SSL_free(my_ssl);
221 | exit(EXIT_SUCCESS);
222 | }
223 |
224 | int main(int argc, char *argv[]) {
225 | char *port = NULL; // The port we should listen on
226 | SSL *my_ssl = NULL;
227 | int my_pid = 0;
228 |
229 | if (argc != 2) {
230 | fprintf(stderr, "Usage: %s port\n",argv[0]); // We should report the problem in a nicer way than report_error
231 | exit(EXIT_FAILURE); // Exit with an error
232 | }
233 |
234 | openssl_init(); // Initialize the OpenSSL library
235 |
236 | port = argv[1]; // Hostname is the first argument
237 |
238 | /*chdir("/etc/auth_server"); // To have the server truly daemonize and chroot to /etc/auth_server,
239 | chroot("/etc/auth_server"); // uncomment these lines, and ensure the cert server.pem is in
240 | daemon(0,0); */ // /etc/auth_server before running.
241 |
242 | for (;;) { // This is our infinite server loop
243 | my_ssl = get_connection(port); // Get the next connection
244 | my_pid = fork();
245 |
246 | if (my_pid == 0) { // If we are the child process
247 | child_process(my_ssl); // then stub out
248 | daemon(0,0); // and daemonize ourselves
249 | } else {
250 | waitpid(my_pid,NULL,0); // Wait for our child to daemonize
251 | }
252 | }
253 |
254 | return 0;
255 | }
256 |
257 |
258 |
259 |
--------------------------------------------------------------------------------
/Chapter13/server/auth_server.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Authentication Client - For testing of the Authentication Server
3 | * By Nathan Yocom, 2004 - For APress Book "The Definitive Guide to Linux Network Programming"
4 | *
5 | * auth_client.h = Maine client header file
6 | */
7 |
8 | #ifndef AUTH_SERVER_H
9 | #define AUTH_SERVER_H
10 |
11 | #include // Include for PAM
12 |
13 | // Setup/Get connections
14 | SSL *get_connection(char *port);
15 | // Authenticate a username/password via PAM
16 | int pam_authenticate_user(const char *,const char *);
17 | // Our PAM Conversation function
18 | int auth_conv(int, const struct pam_message **, struct pam_response **, void *);
19 | // The child processes 'main'
20 | void child_process(SSL *my_ssl);
21 | // The PAM conversation function
22 | int auth_conv(int num_msg,const struct pam_message **msg, struct pam_response **response, void *appdata_ptr);
23 |
24 | // The structure used to pass a username and password to pam
25 | typedef struct auth_struct
26 | {
27 | // Username to authenticate
28 | const char *username;
29 | // Password to use
30 | const char *password;
31 | } auth_struct;
32 |
33 |
34 | #endif
35 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/def-guide-to-linux-network-programming/391555121d25bfa7d296dfd2af42825134cb94ad/LICENSE.txt
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Apress Source Code
2 |
3 | This repository accompanies [*The Definitive Guide to Linux Network Programming*](http://www.apress.com/9781590593226) by Nathan Yocom, John Turner, and Keir Davis (Apress, 2004).
4 |
5 | 
6 |
7 | Download the files as a zip using the green button, or clone the repository to your machine using Git.
8 |
9 | ## Releases
10 |
11 | Release v1.0 corresponds to the code in the published book, without corrections or updates.
12 |
13 | ## Contributions
14 |
15 | See the file Contributing.md for more information on how you can contribute to this repository.
16 |
--------------------------------------------------------------------------------
/contributing.md:
--------------------------------------------------------------------------------
1 | # Contributing to Apress Source Code
2 |
3 | Copyright for Apress source code belongs to the author(s). However, under fair use you are encouraged to fork and contribute minor corrections and updates for the benefit of the author(s) and other readers.
4 |
5 | ## How to Contribute
6 |
7 | 1. Make sure you have a GitHub account.
8 | 2. Fork the repository for the relevant book.
9 | 3. Create a new branch on which to make your change, e.g.
10 | `git checkout -b my_code_contribution`
11 | 4. Commit your change. Include a commit message describing the correction. Please note that if your commit message is not clear, the correction will not be accepted.
12 | 5. Submit a pull request.
13 |
14 | Thank you for your contribution!
--------------------------------------------------------------------------------
/server.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIC/jCCAeYCAQEwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQVUxEzARBgNV
3 | BAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
4 | ZDAeFw0wMzEyMDQxOTM1MTVaFw0wNDAxMDMxOTM1MTVaMEUxCzAJBgNVBAYTAkFV
5 | MRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRz
6 | IFB0eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+t1UWu6YN
7 | RuQ5+UUvYymCffbZAvUcu89FawdICtNb89QX/2g+MtYmFzl4v8Y7XqAeQs/QdBqX
8 | afnWYf4topH6JYbp96ZyB1Vb928gVn7fYl4J6MQITM1Uv0TvTqM1vmD5/5Jv6Xem
9 | /9BfWgSG4kNl8SYZuiJnmNJeIEq1sf7fsqA+8bRDW3zu7tiL9QftrIR0YDX4WX4k
10 | ZKoVs2lVXGcxy5e98w+SMJRuGl/rDu4MVga4DpqrkrwHrs6PyBsJGcYm3v+s1RmS
11 | SRUpljchyEDA1HalaCTZqx95icCLQ+lDsIZM+mjlmg63VVSYGuqcjosqaZ0loeso
12 | dCjZ/UGOSymxAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAHqV6rGXzgP9lLMuabdJ
13 | cJz6kBZOW+jfmI5/ltoa4copsnE+T+QbNzNSdw5ULECyKfEUJe6ySM2xdFml45Po
14 | DIedKiWqxEf/zzfMbUL4lJ3aS2fJtB7M6z1nqSDULb5dwcTkoniMV/eS8onXTzXV
15 | sbh7fnu2RVvDq5s/ja1qRtmnkk3u167y48M/4mvtPiBQ7j4eE73uhLpSid4u0wYa
16 | sG63935SnqhrpK0BVPgIOXIqxdj+x7FGrSNW0j3sggQqt9miZtP5Yia/B7oX6ixu
17 | 0FT38Y7XnTTmH0Nhy2QgrmtWXkvX1qtgH88qCPR6HUDBwCaMuBjXdu8IGKvPhPrD
18 | 0zI=
19 | -----END CERTIFICATE-----
20 | -----BEGIN RSA PRIVATE KEY-----
21 | MIIEowIBAAKCAQEAvrdVFrumDUbkOflFL2Mpgn322QL1HLvPRWsHSArTW/PUF/9o
22 | PjLWJhc5eL/GO16gHkLP0HQal2n51mH+LaKR+iWG6femcgdVW/dvIFZ+32JeCejE
23 | CEzNVL9E706jNb5g+f+Sb+l3pv/QX1oEhuJDZfEmGboiZ5jSXiBKtbH+37KgPvG0
24 | Q1t87u7Yi/UH7ayEdGA1+Fl+JGSqFbNpVVxnMcuXvfMPkjCUbhpf6w7uDFYGuA6a
25 | q5K8B67Oj8gbCRnGJt7/rNUZkkkVKZY3IchAwNR2pWgk2asfeYnAi0PpQ7CGTPpo
26 | 5ZoOt1VUmBrqnI6LKmmdJaHrKHQo2f1BjkspsQIDAQABAoIBAB+cpdb5zaFfwc62
27 | ObiMGEJP/M2lxtk3bDjWb8OKP9R7CwnbRP0iUgrISLdyGjqXCbVaX7XuuMWmREo7
28 | vfT0gHvVIpK/gPBftM9kqR/UFn2SgYHk+jFiAZrthVChWT48SzjFGxG/whyFRJW5
29 | hwyQjplkKmuTRcakNyJw+dE6KsQLPypfp7JqAzgqiikuReluRmi1dmApzXfuuWPe
30 | WPxJpjPDQuyf0/OToyx0v524LR+GoJEtMgOu2TtQZgcWJz6tDFhXE3mSORZki7af
31 | Gf+3bc+KYTZdbnyI/1TIsYS+T/pmQ18w7wdacmJdZ0PR4dX64dVzWCTHd0ToqPDk
32 | zIAjy00CgYEA8S4J+WdmaE7c9A8tyFZpylo+GML+hLpaplaHjr7c4HJ4UE3TsHfY
33 | T0kB227Ge+rCC22vByA2elKFH89tYSbv38Bb4hc+QuUPWSa9PGZT1z//EeqZHbJ7
34 | lrx86GaapJQVbAobtgCNjzzdMFjhu2D/ndlF7H5cDkQqKWj+2sD6FxsCgYEAym91
35 | CAl4eJDB7LHu+piNaYGFd6QQucqn+LQsC7tpVsfGUC8J14pXW12cA/G36vZXA3j+
36 | Mjf8fEocMdbC+a5nwshfcM4VqBJbXGYi8HAmiW+sQK3tJirBn9aqhNOG0i82GmRT
37 | pyDfTdozSi7vhkog/rN0G4wEFp7FNKQRYvxZEyMCgYEAkt4LWuJZnWlw6fqYUag1
38 | sfD0YZXU8jSdYS/OSuH1lYR/ub87CvpgMh/uTpcNrYZO9jCr5jX6ltDLmoxxOjlA
39 | 18vG6E5pLslYaFzL3g0ePzUMefeXmFsJIcjUc52PzGsVBH6/UzzQ94oD1B48ECRI
40 | ZPJbv2FPY6yk1CTJFaNwaEMCgYB3yh6pw9jrF1X594zf83fyz/cnxgkzuA1PqWZL
41 | BvqdpJfgiQU865sn8KvK1bWsr1rsLiPVmbWp4rzubRRxZVf3NlTrzreX/kzbz4Cr
42 | YOIc/90hZQppRHHRYNkEwpsMM23DjkzGIDijvBQPuNh6UdFWhuCVEHS24fr2XIQB
43 | XCxlmwKBgGBU7gpz8vnOjQNyOetLnBEG149subIMIftQLY92OXxTZSG21rgju8CL
44 | C/3FlcN11umLkBxyZUohSALH3UzmifK5PhhmS9tbC+Fx/Cmwma5KabvrpQgoTGNc
45 | Vg/OuAQYo006j9YjkgEg5Sem5agUhjXifgZOErpsLJ7uq9xVysE0
46 | -----END RSA PRIVATE KEY-----
47 | -----BEGIN CERTIFICATE-----
48 | MIIC/jCCAeYCAQEwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQVUxEzARBgNV
49 | BAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
50 | ZDAeFw0wMzEyMDQxOTM1MDlaFw0wNDAxMDMxOTM1MDlaMEUxCzAJBgNVBAYTAkFV
51 | MRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRz
52 | IFB0eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCnoM7W7P9l
53 | Eoa/NAISEIDBGV/nk9ef2ftXc6o1HvugQSKiSRbBVISzSGQMmx64U4Ga2jdFgL1n
54 | l4gLFpD7f0cCPilmnSoR6dMdf46qD9d5UyrJhlFpSXwdxUgz+AoFT8/lBYwDJ83h
55 | Uzo6U5QfwnCsRFhTLIKYraJyF8x+CwZ2Ru9hwd/bznUzhjATxMv51J8odKbyvCnA
56 | mErdeK/5kffXURELNbcxpW/szIflg+H/JP12+9gfJrQGG22aJ1VzX01ldkCn0ew2
57 | p4PtHZWGFfVk5zNgPOtQcLnfdofrfLB2u9rqLSdRHbhFiUYM3jNWcfzE2Ml3DX57
58 | lAglO3/cwpUpAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBABjT6//ZUTzuqY0Tfw6/
59 | bnc6HWCf9eqO+gIejaL/xoHq6r49vSgJ2HON0T7lUnKttSuBnRu+o517YyjEPBTu
60 | DjLF0y3bLYffehK5mfuahqjXDyXkGspvYGBd/W1wjE8v5cGBURFIchatU2s8XwVw
61 | /YrkHMPae3lnq0HOb8r95Af2va6/i6LsEAmB4QAB6SUcAsrBjlhAkIqCXrR1IuQA
62 | fiNkBLQfNOSYveMZJpQ4+NH0vL72iaWOYDOwzJ/+F+trqg61EXCGCHKnfdM6VS87
63 | +0NZyz0KllP3UuLxbvrH49gaggGYVlG85vAAwxv2tU55LpHLxFStr1+hMvFARUC/
64 | +BM=
65 | -----END CERTIFICATE-----
66 |
--------------------------------------------------------------------------------