acl_from_text.c revision 92986
156055Srwatson/*-
274191Srwatson * Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
356055Srwatson * All rights reserved.
456055Srwatson *
556055Srwatson * Redistribution and use in source and binary forms, with or without
656055Srwatson * modification, are permitted provided that the following conditions
756055Srwatson * are met:
856055Srwatson * 1. Redistributions of source code must retain the above copyright
956055Srwatson *    notice, this list of conditions and the following disclaimer.
1056055Srwatson * 2. Redistributions in binary form must reproduce the above copyright
1156055Srwatson *    notice, this list of conditions and the following disclaimer in the
1256055Srwatson *    documentation and/or other materials provided with the distribution.
1356055Srwatson *
1456055Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1556055Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1656055Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1756055Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1856055Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1956055Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2056055Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2156055Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2256055Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2356055Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2456055Srwatson * SUCH DAMAGE.
2556055Srwatson */
2656055Srwatson/*
2766259Srwatson * acl_from_text: Convert a text-form ACL from a string to an acl_t.
2856055Srwatson */
2956055Srwatson
3092986Sobrien#include <sys/cdefs.h>
3192986Sobrien__FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_from_text.c 92986 2002-03-22 21:53:29Z obrien $");
3292986Sobrien
3356055Srwatson#include <sys/types.h>
3475185Stmm#include "namespace.h"
3556055Srwatson#include <sys/acl.h>
3675185Stmm#include "un-namespace.h"
3756055Srwatson#include <sys/errno.h>
3856055Srwatson#include <stdio.h>
3956055Srwatson#include <stdlib.h>
4056055Srwatson#include <string.h>
4156055Srwatson
4256055Srwatson#include "acl_support.h"
4356055Srwatson
4491032Sjedgarstatic acl_tag_t acl_string_to_tag(char *tag, char *qualifier);
4591032Sjedgarstatic char *string_skip_whitespace(char *string);
4691032Sjedgarstatic void string_trim_trailing_whitespace(char *string);
4791032Sjedgar
4856055Srwatsonstatic char *
4956055Srwatsonstring_skip_whitespace(char *string)
5056055Srwatson{
5156055Srwatson
5256055Srwatson	while (*string && ((*string == ' ') || (*string == '\t'))) {
5356055Srwatson		string++;
5456055Srwatson	}
5556055Srwatson	return (string);
5656055Srwatson}
5756055Srwatson
5856055Srwatsonstatic void
5956055Srwatsonstring_trim_trailing_whitespace(char *string)
6056055Srwatson{
6156055Srwatson	char	*end;
6256055Srwatson
6356055Srwatson	if (*string == '\0')
6456055Srwatson		return;
6556055Srwatson
6656055Srwatson	end = string + strlen(string) - 1;
6756055Srwatson
6856055Srwatson	while (end != string) {
6956055Srwatson		if ((*end == ' ') || (*end == '\t')) {
7056055Srwatson			*end = '\0';
7156055Srwatson			end--;
7256055Srwatson		} else {
7356055Srwatson			return;
7456055Srwatson		}
7556055Srwatson	}
7656055Srwatson
7756055Srwatson	return;
7856055Srwatson}
7956055Srwatson
8091032Sjedgarstatic acl_tag_t
8156055Srwatsonacl_string_to_tag(char *tag, char *qualifier)
8256055Srwatson{
8356055Srwatson
8456055Srwatson	if (*qualifier == '\0') {
8556055Srwatson		if ((!strcmp(tag, "user")) || (!strcmp(tag, "u"))) {
8656055Srwatson			return (ACL_USER_OBJ);
8756055Srwatson		} else
8856055Srwatson		if ((!strcmp(tag, "group")) || (!strcmp(tag, "g"))) {
8956055Srwatson			return (ACL_GROUP_OBJ);
9056055Srwatson		} else
9156055Srwatson		if ((!strcmp(tag, "mask")) || (!strcmp(tag, "m"))) {
9256055Srwatson			return (ACL_MASK);
9356055Srwatson		} else
9456055Srwatson		if ((!strcmp(tag, "other")) || (!strcmp(tag, "o"))) {
9556055Srwatson			return (ACL_OTHER);
9656055Srwatson		} else
9756055Srwatson			return(-1);
9856055Srwatson	} else {
9956055Srwatson		if ((!strcmp(tag, "user")) || (!strcmp(tag, "u"))) {
10056055Srwatson			return(ACL_USER);
10156055Srwatson		} else
10256055Srwatson		if ((!strcmp(tag, "group")) || (!strcmp(tag, "g"))) {
10356055Srwatson			return(ACL_GROUP);
10456055Srwatson		} else
10556055Srwatson			return(-1);
10656055Srwatson	}
10756055Srwatson}
10856055Srwatson
10956055Srwatson/*
11066259Srwatson * acl_from_text -- Convert a string into an ACL.
11166259Srwatson * Postpone most validity checking until the end and call acl_valid() to do
11256055Srwatson * that.
11356055Srwatson */
11456055Srwatsonacl_t
11556055Srwatsonacl_from_text(const char *buf_p)
11656055Srwatson{
11775928Sjedgar	acl_tag_t	 t;
11875928Sjedgar	acl_perm_t	 p;
11975928Sjedgar	acl_t		 acl;
12075928Sjedgar	char		*mybuf_p, *line, *cur, *notcomment, *comment, *entry;
12175928Sjedgar	char		*tag, *qualifier, *permission;
12275928Sjedgar	int		 error;
12375928Sjedgar	uid_t		 id;
12456055Srwatson
12566259Srwatson	/* Local copy we can mess up. */
12656055Srwatson	mybuf_p = strdup(buf_p);
12791034Sjedgar	if (mybuf_p == NULL)
12871142Srwatson		return(NULL);
12956055Srwatson
13056055Srwatson	acl = acl_init(3);
13191034Sjedgar	if (acl == NULL) {
13256055Srwatson		free(mybuf_p);
13371142Srwatson		return(NULL);
13456055Srwatson	}
13556055Srwatson
13666259Srwatson	/* Outer loop: delimit at \n boundaries. */
13756055Srwatson	cur = mybuf_p;
13856055Srwatson	while ((line = strsep(&cur, "\n"))) {
13966259Srwatson		/* Now split the line on the first # to strip out comments. */
14056055Srwatson		comment = line;
14156055Srwatson		notcomment = strsep(&comment, "#");
14256055Srwatson
14366259Srwatson		/* Inner loop: delimit at ',' boundaries. */
14456055Srwatson		while ((entry = strsep(&notcomment, ","))) {
14566259Srwatson			/* Now split into three ':' delimited fields. */
14656055Srwatson			tag = strsep(&entry, ":");
14791034Sjedgar			if (tag == NULL) {
14856055Srwatson				errno = EINVAL;
14956055Srwatson				goto error_label;
15056055Srwatson			}
15156055Srwatson			tag = string_skip_whitespace(tag);
15256055Srwatson			if ((*tag == '\0') && (!entry)) {
15356055Srwatson				/*
15466259Srwatson				 * Is an entirely comment line, skip to next
15566259Srwatson				 * comma.
15656055Srwatson				 */
15756055Srwatson				continue;
15856055Srwatson			}
15956055Srwatson			string_trim_trailing_whitespace(tag);
16056055Srwatson
16156055Srwatson			qualifier = strsep(&entry, ":");
16291034Sjedgar			if (qualifier == NULL) {
16356055Srwatson				errno = EINVAL;
16456055Srwatson				goto error_label;
16556055Srwatson			}
16656055Srwatson			qualifier = string_skip_whitespace(qualifier);
16756055Srwatson			string_trim_trailing_whitespace(qualifier);
16856055Srwatson
16956055Srwatson			permission = strsep(&entry, ":");
17091034Sjedgar			if (permission == NULL || entry) {
17156055Srwatson				errno = EINVAL;
17256055Srwatson				goto error_label;
17356055Srwatson			}
17456055Srwatson			permission = string_skip_whitespace(permission);
17556055Srwatson			string_trim_trailing_whitespace(permission);
17656055Srwatson
17756055Srwatson			t = acl_string_to_tag(tag, qualifier);
17856055Srwatson			if (t == -1) {
17956055Srwatson				errno = EINVAL;
18056055Srwatson				goto error_label;
18156055Srwatson			}
18256055Srwatson
18374191Srwatson			error = _posix1e_acl_string_to_perm(permission, &p);
18456055Srwatson			if (error == -1) {
18556055Srwatson				errno = EINVAL;
18656055Srwatson				goto error_label;
18756055Srwatson			}
18856055Srwatson
18956055Srwatson			switch(t) {
19056055Srwatson			case ACL_USER_OBJ:
19156055Srwatson			case ACL_GROUP_OBJ:
19256055Srwatson			case ACL_MASK:
19356055Srwatson			case ACL_OTHER:
19456055Srwatson				if (*qualifier != '\0') {
19556055Srwatson					errno = EINVAL;
19656055Srwatson					goto error_label;
19756055Srwatson				}
19856055Srwatson				id = 0;
19956055Srwatson				break;
20056055Srwatson
20156055Srwatson			case ACL_USER:
20256055Srwatson			case ACL_GROUP:
20374191Srwatson				error = _posix1e_acl_name_to_id(t, qualifier,
20474191Srwatson				    &id);
20556055Srwatson				if (error == -1)
20656055Srwatson					goto error_label;
20756055Srwatson				break;
20856055Srwatson
20956055Srwatson			default:
21056055Srwatson				errno = EINVAL;
21156055Srwatson				goto error_label;
21256055Srwatson			}
21356055Srwatson
21474191Srwatson			error = _posix1e_acl_add_entry(acl, t, id, p);
21556055Srwatson			if (error == -1)
21656055Srwatson				goto error_label;
21756055Srwatson		}
21856055Srwatson	}
21956055Srwatson
22056055Srwatson#if 0
22166259Srwatson	/* XXX Should we only return ACLs valid according to acl_valid? */
22266259Srwatson	/* Verify validity of the ACL we read in. */
22356055Srwatson	if (acl_valid(acl) == -1) {
22456055Srwatson		errno = EINVAL;
22556055Srwatson		goto error_label;
22656055Srwatson	}
22756055Srwatson#endif
22856055Srwatson
22956055Srwatson	return(acl);
23056055Srwatson
23156055Srwatsonerror_label:
23256055Srwatson	acl_free(acl);
23356055Srwatson	free(mybuf_p);
23471142Srwatson	return(NULL);
23556055Srwatson}
23656055Srwatson
23756055Srwatson
23856055Srwatson
239