1/*
2 *
3 *   Copyright (c) International Business Machines  Corp., 2004
4 *
5 *   This program is free software;  you can redistribute it and/or modify
6 *   it under the terms of the GNU General Public License as published by
7 *   the Free Software Foundation; either version 2 of the License, or
8 *   (at your option) any later version.
9 *
10 *   This program is distributed in the hope that it will be useful,
11 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13 *   the GNU General Public License for more details.
14 *
15 *   You should have received a copy of the GNU General Public License
16 *   along with this program;  if not, write to the Free Software
17 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20/*
21 * Test Name: bind02
22 *
23 * Test Description:
24 *  Make sure bind() gives EACCESS error for (non-root) users.
25 *
26 * Usage:  <for command-line>
27 *  bind01 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
28 *     where,  -c n : Run n copies concurrently.
29 *             -e   : Turn on errno logging.
30 *             -i n : Execute test n times.
31 *             -I x : Execute test for x seconds.
32 *             -P x : Pause for x seconds between iterations.
33 *             -t   : Turn on syscall timing.
34 *
35 * HISTORY
36 *      07/2004 Written by Dan Jones
37 *      07/2004 Ported to LTP format by Robbie Williamson
38 *
39 * RESTRICTIONS:
40 *  None.
41 *
42 */
43
44#include <stdio.h>
45#include <stdlib.h>
46#include <unistd.h>
47#include <errno.h>
48#include <fcntl.h>
49#include <pwd.h>
50#include <grp.h>
51
52#include <sys/types.h>
53#include <sys/socket.h>
54#include <sys/un.h>
55
56#include <netinet/in.h>
57
58#include "test.h"
59
60char *TCID = "bind02";
61int testno;
62int TST_TOTAL = 1;
63
64/* This port needs to be a Privledged port */
65#define TCP_PRIVLEGED_COM_PORT 463
66
67struct passwd *pw;
68struct group *gr;
69
70uid_t uid;
71gid_t gid;
72
73int rc;
74
75void try_bind(void)
76{
77	struct sockaddr_in servaddr;
78	int sockfd, r_value;
79
80	// Set effective user/group
81	if ((rc = setegid(gid)) == -1) {
82		tst_brkm(TBROK | TERRNO, 0, "setegid(%u) failed", gid);
83	}
84	if ((rc = seteuid(uid)) == -1) {
85		tst_brkm(TBROK | TERRNO, 0, "seteuid(%u) failed", uid);
86	}
87
88	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
89		tst_brkm(TBROK | TERRNO, 0, "socket() failed");
90	}
91
92	memset(&servaddr, 0, sizeof(servaddr));
93	servaddr.sin_family = AF_INET;
94	servaddr.sin_port = htons(TCP_PRIVLEGED_COM_PORT);
95	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
96	r_value = bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
97	if (r_value) {
98		if (errno == EACCES) {
99			tst_resm(TPASS, "correct error");
100		} else {
101			tst_resm(TFAIL, "incorrect error, %d", r_value);
102		}
103	} else {
104		tst_resm(TFAIL, "user was able to bind successfully");
105	}
106
107	close(sockfd);
108
109	// Set effective user/group
110	if ((rc = setegid(0)) == -1) {
111		tst_brkm(TBROK | TERRNO, 0, "setegid(0) reset failed");
112	}
113	if ((rc = seteuid(uid)) == -1) {
114		/* XXX: is this seteuid() correct !?  it isnt a reset if we
115		 *      made the same exact call above ...
116		 */
117		tst_brkm(TBROK | TERRNO, 0, "seteuid(%u) reset failed", uid);
118	}
119
120}
121
122int main(int argc, char *argv[])
123{
124	char *username = "nobody";
125
126	tst_parse_opts(argc, argv, NULL, NULL);
127
128	tst_require_root();
129
130	if ((pw = getpwnam(username)) == NULL) {
131		tst_brkm(TBROK, 0, "Username - %s - not found", username);
132	}
133
134	if ((gr = getgrgid(pw->pw_gid)) == NULL) {
135		tst_brkm(TBROK | TERRNO, 0, "getgrgid(%u) failed", pw->pw_gid);
136	}
137
138	uid = pw->pw_uid;
139	gid = gr->gr_gid;
140
141	tst_resm(TINFO, "Socket will try to be bind by user: %s, group: %s",
142		 pw->pw_name, gr->gr_name);
143
144	try_bind();
145	tst_exit();
146}
147