1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include "selinux_internal.h"
5#include "context_internal.h"
6#include <selinux/get_context_list.h>
7
8/* context_menu - given a list of contexts, presents a menu of security contexts
9 *            to the user.  Returns the number (position in the list) of
10 *            the user selected context.
11 */
12static int context_menu(char ** list)
13{
14	int i;			/* array index                        */
15	int choice = 0;		/* index of the user's choice         */
16	char response[10];	/* string to hold the user's response */
17
18	printf("\n\n");
19	for (i = 0; list[i]; i++)
20		printf("[%d] %s\n", i + 1, list[i]);
21
22	while ((choice < 1) || (choice > i)) {
23		printf("Enter number of choice: ");
24		fflush(stdin);
25		if (fgets(response, sizeof(response), stdin) == NULL)
26			continue;
27		fflush(stdin);
28		choice = strtol(response, NULL, 10);
29	}
30
31	return (choice - 1);
32}
33
34/* query_user_context - given a list of context, allow the user to choose one.  The
35 *                  default is the first context in the list.  Returns 0 on
36 *                  success, -1 on failure
37 */
38int query_user_context(char ** list, char ** usercon)
39{
40	char response[10];	/* The user's response                        */
41	int choice;		/* The index in the list of the sid chosen by
42				   the user                                   */
43
44	if (!list[0])
45		return -1;
46
47	printf("\nYour default context is %s.\n", list[0]);
48	if (list[1]) {
49		printf("Do you want to choose a different one? [n]");
50		fflush(stdin);
51		if (fgets(response, sizeof(response), stdin) == NULL)
52			return -1;
53		fflush(stdin);
54
55		if ((response[0] == 'y') || (response[0] == 'Y')) {
56			choice = context_menu(list);
57			*usercon = strdup(list[choice]);
58			if (!(*usercon))
59				return -1;
60			return 0;
61		}
62
63		*usercon = strdup(list[0]);
64		if (!(*usercon))
65			return -1;
66	} else {
67		*usercon = strdup(list[0]);
68		if (!(*usercon))
69			return -1;
70	}
71
72	return 0;
73}
74
75/* get_field - given fieldstr - the "name" of a field, query the user
76 *             and set the new value of the field
77 */
78static void get_field(const char *fieldstr, char *newfield, int newfieldlen)
79{
80	int done = 0;		/* true if a non-empty field has been obtained */
81
82	while (!done) {		/* Keep going until we get a value for the field */
83		printf("\tEnter %s ", fieldstr);
84		fflush(stdin);
85		if (fgets(newfield, newfieldlen, stdin) == NULL)
86			continue;
87		fflush(stdin);
88		if (newfield[strlen(newfield) - 1] == '\n')
89			newfield[strlen(newfield) - 1] = '\0';
90
91		if (strlen(newfield) == 0) {
92			printf("You must enter a %s\n", fieldstr);
93		} else {
94			done = 1;
95		}
96	}
97}
98
99/* manual_user_enter_context - provides a way for a user to manually enter a
100 *                     context in case the policy doesn't allow a list
101 *                     to be obtained.
102 *                     given the userid, queries the user and places the
103 *                     context chosen by the user into usercon.  Returns 0
104 *                     on success.
105 */
106int manual_user_enter_context(const char *user, char ** newcon)
107{
108	char response[10];	/* Used to get yes or no answers from user */
109	char role[100];		/* The role requested by the user          */
110	int rolelen = 100;
111	char type[100];		/* The type requested by the user          */
112	int typelen = 100;
113	char level[100];	/* The level requested by the user         */
114	int levellen = 100;
115	int mls_enabled = is_selinux_mls_enabled();
116
117	context_t new_context;	/* The new context chosen by the user     */
118	char *user_context = NULL;	/* String value of the user's context     */
119	int done = 0;		/* true if a valid sid has been obtained  */
120
121	/* Initialize the context.  How this is done depends on whether
122	   or not MLS is enabled                                        */
123	if (mls_enabled)
124		new_context = context_new("user:role:type:level");
125	else
126		new_context = context_new("user:role:type");
127
128	if (!new_context)
129		return -1;
130
131	while (!done) {
132		printf("Would you like to enter a security context? [y]");
133		if (fgets(response, sizeof(response), stdin) == NULL
134		    || (response[0] == 'n') || (response[0] == 'N')) {
135			context_free(new_context);
136			return -1;
137		}
138
139		/* Allow the user to enter each field of the context individually */
140		if (context_user_set(new_context, user)) {
141			context_free(new_context);
142			return -1;
143		}
144		get_field("role", role, rolelen);
145		if (context_role_set(new_context, role)) {
146			context_free(new_context);
147			return -1;
148		}
149		get_field("type", type, typelen);
150		if (context_type_set(new_context, type)) {
151			context_free(new_context);
152			return -1;
153		}
154
155		if (mls_enabled) {
156			get_field("level", level, levellen);
157			if (context_range_set(new_context, level)) {
158				context_free(new_context);
159				return -1;
160			}
161		}
162
163		/* Get the string value of the context and see if it is valid. */
164		user_context = context_str(new_context);
165		if (!user_context) {
166			context_free(new_context);
167			return -1;
168		}
169		if (!security_check_context(user_context))
170			done = 1;
171		else
172			printf("Not a valid security context\n");
173	}
174
175	*newcon = strdup(user_context);
176	context_free(new_context);
177	if (!(*newcon))
178		return -1;
179	return 0;
180}
181