1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2013 RackTop Systems.
24 */
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <strings.h>
29#include <auth_attr.h>
30#include <prof_attr.h>
31#include <user_attr.h>
32#include <project.h>
33#include <secdb.h>
34#include <pwd.h>
35#include <unistd.h>
36#include <priv.h>
37#include <errno.h>
38#include <ctype.h>
39#include <nss.h>
40#include <bsm/libbsm.h>
41#include <tsol/label.h>
42#include "funcs.h"
43#include "messages.h"
44#undef	GROUP
45#include "userdefs.h"
46
47typedef struct ua_key {
48	const char	*key;
49	const char	*(*check)(const char *);
50	const char	*errstr;
51	char		*newvalue;
52} ua_key_t;
53
54static const char role[] = "role name";
55static const char prof[] = "profile name";
56static const char proj[] = "project name";
57static const char priv[] = "privilege set";
58static const char auth[] = "authorization";
59static const char type[] = "user type";
60static const char lock[] = "lock_after_retries value";
61static const char label[] = "label";
62static const char auditflags[] = "audit mask";
63static char	  auditerr[256];
64
65
66static const char *check_auth(const char *);
67static const char *check_prof(const char *);
68static const char *check_role(const char *);
69static const char *check_proj(const char *);
70static const char *check_privset(const char *);
71static const char *check_type(const char *);
72static const char *check_lock_after_retries(const char *);
73static const char *check_label(const char *);
74static const char *check_auditflags(const char *);
75
76int nkeys;
77
78static ua_key_t keys[] = {
79	/* First entry is always set correctly in main() */
80	{ USERATTR_TYPE_KW,	check_type,	type },
81	{ USERATTR_AUTHS_KW,	check_auth,	auth },
82	{ USERATTR_PROFILES_KW,	check_prof,	prof },
83	{ USERATTR_ROLES_KW,	check_role,	role },
84	{ USERATTR_DEFAULTPROJ_KW,	check_proj,	proj },
85	{ USERATTR_LIMPRIV_KW,	check_privset,	priv },
86	{ USERATTR_DFLTPRIV_KW,	check_privset,	priv },
87	{ USERATTR_LOCK_AFTER_RETRIES_KW, check_lock_after_retries,  lock },
88	{ USERATTR_CLEARANCE,	check_label,	label },
89	{ USERATTR_MINLABEL,	check_label,	label },
90	{ USERATTR_AUDIT_FLAGS_KW, check_auditflags, auditflags },
91};
92
93#define	NKEYS	(sizeof (keys)/sizeof (ua_key_t))
94
95/*
96 * Change a key, there are three different call sequences:
97 *
98 *		key, value	- key with option letter, value.
99 *		NULL, value	- -K key=value option.
100 */
101
102void
103change_key(const char *key, char *value)
104{
105	int i;
106	const char *res;
107
108	if (key == NULL) {
109		key = value;
110		value = strchr(value, '=');
111		/* Bad value */
112		if (value == NULL) {
113			errmsg(M_INVALID_VALUE);
114			exit(EX_BADARG);
115		}
116		*value++ = '\0';
117	}
118
119	for (i = 0; i < NKEYS; i++) {
120		if (strcmp(key, keys[i].key) == 0) {
121			if (keys[i].newvalue != NULL) {
122				/* Can't set a value twice */
123				errmsg(M_REDEFINED_KEY, key);
124				exit(EX_BADARG);
125			}
126
127			if (keys[i].check != NULL &&
128			    (res = keys[i].check(value)) != NULL) {
129				errmsg(M_INVALID, res, keys[i].errstr);
130				exit(EX_BADARG);
131			}
132			keys[i].newvalue = value;
133			nkeys++;
134			return;
135		}
136	}
137	errmsg(M_INVALID_KEY, key);
138	exit(EX_BADARG);
139}
140
141/*
142 * Add the keys to the argument vector.
143 */
144void
145addkey_args(char **argv, int *index)
146{
147	int i;
148
149	for (i = 0; i < NKEYS; i++) {
150		const char *key = keys[i].key;
151		char *val = keys[i].newvalue;
152		size_t len;
153		char *arg;
154
155		if (val == NULL)
156			continue;
157
158		len = strlen(key) + strlen(val) + 2;
159		arg = malloc(len);
160
161		(void) snprintf(arg, len, "%s=%s", key, val);
162		argv[(*index)++] = "-K";
163		argv[(*index)++] = arg;
164	}
165}
166
167/*
168 * Propose a default value for a key and get the actual value back.
169 * If the proposed default value is NULL, return the actual value set.
170 * The key argument is the user_attr key.
171 */
172char *
173getsetdefval(const char *key, char *dflt)
174{
175	int i;
176
177	for (i = 0; i < NKEYS; i++)
178		if (strcmp(keys[i].key, key) == 0) {
179			if (keys[i].newvalue != NULL)
180				return (keys[i].newvalue);
181			else
182				return (keys[i].newvalue = dflt);
183		}
184	return (NULL);
185}
186
187char *
188getusertype(char *cmdname)
189{
190	static char usertype[MAX_TYPE_LENGTH];
191	char *cmd;
192
193	if ((cmd = strrchr(cmdname, '/')))
194		++cmd;
195	else
196		cmd = cmdname;
197
198	/* get user type based on the program name */
199	if (strncmp(cmd, CMD_PREFIX_USER,
200	    strlen(CMD_PREFIX_USER)) == 0)
201		strcpy(usertype, USERATTR_TYPE_NORMAL_KW);
202	else
203		strcpy(usertype, USERATTR_TYPE_NONADMIN_KW);
204
205	return (usertype);
206}
207
208int
209is_role(char *usertype)
210{
211	if (strcmp(usertype, USERATTR_TYPE_NONADMIN_KW) == 0)
212		return (1);
213	/* not a role */
214	return (0);
215}
216
217/*
218 * Verifies the provided list of authorizations are all valid.
219 *
220 * Returns NULL if all authorization names are valid.
221 * Otherwise, returns the invalid authorization name
222 *
223 */
224static const char *
225check_auth(const char *auths)
226{
227	char *authname;
228	authattr_t *result;
229	char *tmp;
230	struct passwd   *pw;
231	int have_grant = 0;
232
233	tmp = strdup(auths);
234	if (tmp == NULL) {
235		errmsg(M_NOSPACE);
236		exit(EX_FAILURE);
237	}
238
239	authname = strtok(tmp, AUTH_SEP);
240	pw = getpwuid(getuid());
241	if (pw == NULL) {
242		return (authname);
243	}
244
245	while (authname != NULL) {
246		char *suffix;
247		char *authtoks;
248
249		/* Check if user has been granted this authorization */
250		if (!chkauthattr(authname, pw->pw_name))
251			return (authname);
252
253		/* Remove named object after slash */
254		if ((suffix = index(authname, KV_OBJECTCHAR)) != NULL)
255			*suffix = '\0';
256
257		/* Find the suffix */
258		if ((suffix = rindex(authname, '.')) == NULL)
259			return (authname);
260
261		/* Check for existence in auth_attr */
262		suffix++;
263		if (strcmp(suffix, KV_WILDCARD)) { /* Not a wildcard */
264			result = getauthnam(authname);
265			if (result == NULL) {
266			/* can't find the auth */
267				free_authattr(result);
268				return (authname);
269			}
270			free_authattr(result);
271		}
272
273		/* Check if user can delegate this authorization */
274		if (strcmp(suffix, "grant")) { /* Not a grant option */
275			authtoks = malloc(strlen(authname) + sizeof ("grant"));
276			strcpy(authtoks, authname);
277			have_grant = 0;
278			while ((suffix = rindex(authtoks, '.')) &&
279			    !have_grant) {
280				strcpy(suffix, ".grant");
281				if (chkauthattr(authtoks, pw->pw_name))
282					have_grant = 1;
283				else
284					*suffix = '\0';
285			}
286			if (!have_grant)
287				return (authname);
288		}
289		authname = strtok(NULL, AUTH_SEP);
290	}
291	free(tmp);
292	return (NULL);
293}
294
295/*
296 * Verifies the provided list of profile names are valid.
297 *
298 * Returns NULL if all profile names are valid.
299 * Otherwise, returns the invalid profile name
300 *
301 */
302static const char *
303check_prof(const char *profs)
304{
305	char *profname;
306	profattr_t *result;
307	char *tmp;
308
309	tmp = strdup(profs);
310	if (tmp == NULL) {
311		errmsg(M_NOSPACE);
312		exit(EX_FAILURE);
313	}
314
315	profname = strtok(tmp, PROF_SEP);
316	while (profname != NULL) {
317		result = getprofnam(profname);
318		if (result == NULL) {
319		/* can't find the profile */
320			return (profname);
321		}
322		free_profattr(result);
323		profname = strtok(NULL, PROF_SEP);
324	}
325	free(tmp);
326	return (NULL);
327}
328
329
330/*
331 * Verifies the provided list of role names are valid.
332 *
333 * Returns NULL if all role names are valid.
334 * Otherwise, returns the invalid role name
335 *
336 */
337static const char *
338check_role(const char *roles)
339{
340	char *rolename;
341	userattr_t *result;
342	char *utype;
343	char *tmp;
344
345	tmp = strdup(roles);
346	if (tmp == NULL) {
347		errmsg(M_NOSPACE);
348		exit(EX_FAILURE);
349	}
350
351	rolename = strtok(tmp, ROLE_SEP);
352	while (rolename != NULL) {
353		result = getusernam(rolename);
354		if (result == NULL) {
355		/* can't find the rolename */
356			return (rolename);
357		}
358		/* Now, make sure it is a role */
359		utype = kva_match(result->attr, USERATTR_TYPE_KW);
360		if (utype == NULL) {
361			/* no user type defined. not a role */
362			free_userattr(result);
363			return (rolename);
364		}
365		if (strcmp(utype, USERATTR_TYPE_NONADMIN_KW) != 0) {
366			free_userattr(result);
367			return (rolename);
368		}
369		free_userattr(result);
370		rolename = strtok(NULL, ROLE_SEP);
371	}
372	free(tmp);
373	return (NULL);
374}
375
376static const char *
377check_proj(const char *proj)
378{
379	if (getprojidbyname(proj) < 0) {
380		return (proj);
381	} else {
382		return (NULL);
383	}
384}
385
386static const char *
387check_privset(const char *pset)
388{
389	priv_set_t *tmp;
390	const char *res;
391
392	tmp = priv_str_to_set(pset, ",", &res);
393
394	if (tmp != NULL) {
395		res = NULL;
396		priv_freeset(tmp);
397	} else if (res == NULL)
398		res = strerror(errno);
399
400	return (res);
401}
402
403static const char *
404check_type(const char *type)
405{
406	if (strcmp(type, USERATTR_TYPE_NONADMIN_KW) != 0 &&
407	    strcmp(type, USERATTR_TYPE_NORMAL_KW) != 0)
408		return (type);
409
410	return (NULL);
411}
412
413static const char *
414check_lock_after_retries(const char *keyval)
415{
416	if (keyval != NULL) {
417		if ((strcasecmp(keyval, "no") != 0) &&
418		    (strcasecmp(keyval, "yes") != 0) &&
419		    (*keyval != '\0'))   {
420			return (keyval);
421		}
422	}
423	return (NULL);
424}
425
426static const char *
427check_label(const char *labelstr)
428{
429	int	err;
430	m_label_t *lbl = NULL;
431
432	if (!is_system_labeled())
433		return (NULL);
434
435	err = str_to_label(labelstr, &lbl, MAC_LABEL, L_NO_CORRECTION, NULL);
436	m_label_free(lbl);
437
438	if (err == -1)
439		return (labelstr);
440
441	return (NULL);
442}
443
444static const char *
445check_auditflags(const char *auditflags)
446{
447	au_mask_t mask;
448	char	*flags;
449	char	*last = NULL;
450	char	*err = "NULL";
451
452	/* if deleting audit_flags */
453	if (*auditflags == '\0') {
454		return (NULL);
455	}
456
457	if ((flags = _strdup_null((char *)auditflags)) == NULL) {
458		errmsg(M_NOSPACE);
459		exit(EX_FAILURE);
460	}
461
462	if (!__chkflags(_strtok_escape(flags, KV_AUDIT_DELIMIT, &last), &mask,
463	    B_FALSE, &err)) {
464		(void) snprintf(auditerr, sizeof (auditerr),
465		    "always mask \"%s\"", err);
466		free(flags);
467		return (auditerr);
468	}
469	if (!__chkflags(_strtok_escape(NULL, KV_AUDIT_DELIMIT, &last), &mask,
470	    B_FALSE, &err)) {
471		(void) snprintf(auditerr, sizeof (auditerr),
472		    "never mask \"%s\"", err);
473		free(flags);
474		return (auditerr);
475	}
476	if (last != NULL) {
477		(void) snprintf(auditerr, sizeof (auditerr), "\"%s\"",
478		    auditflags);
479		free(flags);
480		return (auditerr);
481	}
482	free(flags);
483
484	return (NULL);
485}
486