acl_from_text.c revision 66259
156055Srwatson/*-
266259Srwatson * Copyright (c) 1999, 2000 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 *
2666259Srwatson * $FreeBSD: head/lib/libc/posix1e/acl_from_text.c 66259 2000-09-22 16:36:04Z rwatson $
2756055Srwatson */
2856055Srwatson/*
2966259Srwatson * acl_from_text: Convert a text-form ACL from a string to an acl_t.
3056055Srwatson */
3156055Srwatson
3256055Srwatson#include <sys/types.h>
3356055Srwatson#include <sys/acl.h>
3456055Srwatson#include <sys/errno.h>
3556055Srwatson#include <stdio.h>
3656055Srwatson#include <stdlib.h>
3756055Srwatson#include <string.h>
3856055Srwatson
3956055Srwatson#include "acl_support.h"
4056055Srwatson
4156055Srwatsonstatic char *
4256055Srwatsonstring_skip_whitespace(char *string)
4356055Srwatson{
4456055Srwatson
4556055Srwatson	while (*string && ((*string == ' ') || (*string == '\t'))) {
4656055Srwatson		string++;
4756055Srwatson	}
4856055Srwatson	return (string);
4956055Srwatson}
5056055Srwatson
5156055Srwatsonstatic void
5256055Srwatsonstring_trim_trailing_whitespace(char *string)
5356055Srwatson{
5456055Srwatson	char	*end;
5556055Srwatson
5656055Srwatson	if (*string == '\0')
5756055Srwatson		return;
5856055Srwatson
5956055Srwatson	end = string + strlen(string) - 1;
6056055Srwatson
6156055Srwatson	while (end != string) {
6256055Srwatson		if ((*end == ' ') || (*end == '\t')) {
6356055Srwatson			*end = '\0';
6456055Srwatson			end--;
6556055Srwatson		} else {
6656055Srwatson			return;
6756055Srwatson		}
6856055Srwatson	}
6956055Srwatson
7056055Srwatson	return;
7156055Srwatson}
7256055Srwatson
7356055Srwatsonacl_tag_t
7456055Srwatsonacl_string_to_tag(char *tag, char *qualifier)
7556055Srwatson{
7656055Srwatson
7756055Srwatson	if (*qualifier == '\0') {
7856055Srwatson		if ((!strcmp(tag, "user")) || (!strcmp(tag, "u"))) {
7956055Srwatson			return (ACL_USER_OBJ);
8056055Srwatson		} else
8156055Srwatson		if ((!strcmp(tag, "group")) || (!strcmp(tag, "g"))) {
8256055Srwatson			return (ACL_GROUP_OBJ);
8356055Srwatson		} else
8456055Srwatson		if ((!strcmp(tag, "mask")) || (!strcmp(tag, "m"))) {
8556055Srwatson			return (ACL_MASK);
8656055Srwatson		} else
8756055Srwatson		if ((!strcmp(tag, "other")) || (!strcmp(tag, "o"))) {
8856055Srwatson			return (ACL_OTHER);
8956055Srwatson		} else
9056055Srwatson			return(-1);
9156055Srwatson	} else {
9256055Srwatson		if ((!strcmp(tag, "user")) || (!strcmp(tag, "u"))) {
9356055Srwatson			return(ACL_USER);
9456055Srwatson		} else
9556055Srwatson		if ((!strcmp(tag, "group")) || (!strcmp(tag, "g"))) {
9656055Srwatson			return(ACL_GROUP);
9756055Srwatson		} else
9856055Srwatson			return(-1);
9956055Srwatson	}
10056055Srwatson}
10156055Srwatson
10256055Srwatson/*
10366259Srwatson * acl_from_text -- Convert a string into an ACL.
10466259Srwatson * Postpone most validity checking until the end and call acl_valid() to do
10556055Srwatson * that.
10656055Srwatson */
10756055Srwatsonacl_t
10856055Srwatsonacl_from_text(const char *buf_p)
10956055Srwatson{
11056055Srwatson	acl_tag_t	t;
11156055Srwatson	acl_perm_t	p;
11256055Srwatson	acl_t	acl;
11356055Srwatson	uid_t	id;
11456055Srwatson	char	*mybuf_p, *line, *cur, *notcomment, *comment, *entry;
11556055Srwatson	char	*tag, *qualifier, *permission;
11656055Srwatson	int	error;
11756055Srwatson
11866259Srwatson	/* Local copy we can mess up. */
11956055Srwatson	mybuf_p = strdup(buf_p);
12056055Srwatson	if (!mybuf_p) {
12156055Srwatson		errno = ENOMEM;
12256055Srwatson		return(0);
12356055Srwatson	}
12456055Srwatson
12556055Srwatson	acl = acl_init(3);
12656055Srwatson	if (!acl) {
12756055Srwatson		free(mybuf_p);
12856055Srwatson		errno = ENOMEM;
12956055Srwatson		return(0);
13056055Srwatson	}
13156055Srwatson
13266259Srwatson	/* Outer loop: delimit at \n boundaries. */
13356055Srwatson	cur = mybuf_p;
13456055Srwatson	while ((line = strsep(&cur, "\n"))) {
13566259Srwatson		/* Now split the line on the first # to strip out comments. */
13656055Srwatson		comment = line;
13756055Srwatson		notcomment = strsep(&comment, "#");
13856055Srwatson
13966259Srwatson		/* Inner loop: delimit at ',' boundaries. */
14056055Srwatson		while ((entry = strsep(&notcomment, ","))) {
14166259Srwatson			/* Now split into three ':' delimited fields. */
14256055Srwatson			tag = strsep(&entry, ":");
14356055Srwatson			if (!tag) {
14456055Srwatson				errno = EINVAL;
14556055Srwatson				goto error_label;
14656055Srwatson			}
14756055Srwatson			tag = string_skip_whitespace(tag);
14856055Srwatson			if ((*tag == '\0') && (!entry)) {
14956055Srwatson				/*
15066259Srwatson				 * Is an entirely comment line, skip to next
15166259Srwatson				 * comma.
15256055Srwatson				 */
15356055Srwatson				continue;
15456055Srwatson			}
15556055Srwatson			string_trim_trailing_whitespace(tag);
15656055Srwatson
15756055Srwatson			qualifier = strsep(&entry, ":");
15856055Srwatson			if (!qualifier) {
15956055Srwatson				errno = EINVAL;
16056055Srwatson				goto error_label;
16156055Srwatson			}
16256055Srwatson			qualifier = string_skip_whitespace(qualifier);
16356055Srwatson			string_trim_trailing_whitespace(qualifier);
16456055Srwatson
16556055Srwatson			permission = strsep(&entry, ":");
16656055Srwatson			if ((!permission) || (entry)) {
16756055Srwatson				errno = EINVAL;
16856055Srwatson				goto error_label;
16956055Srwatson			}
17056055Srwatson			permission = string_skip_whitespace(permission);
17156055Srwatson			string_trim_trailing_whitespace(permission);
17256055Srwatson
17356055Srwatson			t = acl_string_to_tag(tag, qualifier);
17456055Srwatson			if (t == -1) {
17556055Srwatson				errno = EINVAL;
17656055Srwatson				goto error_label;
17756055Srwatson			}
17856055Srwatson
17956055Srwatson			error = acl_string_to_perm(permission, &p);
18056055Srwatson			if (error == -1) {
18156055Srwatson				errno = EINVAL;
18256055Srwatson				goto error_label;
18356055Srwatson			}
18456055Srwatson
18556055Srwatson			switch(t) {
18656055Srwatson			case ACL_USER_OBJ:
18756055Srwatson			case ACL_GROUP_OBJ:
18856055Srwatson			case ACL_MASK:
18956055Srwatson			case ACL_OTHER:
19056055Srwatson				if (*qualifier != '\0') {
19156055Srwatson					errno = EINVAL;
19256055Srwatson					goto error_label;
19356055Srwatson				}
19456055Srwatson				id = 0;
19556055Srwatson				break;
19656055Srwatson
19756055Srwatson			case ACL_USER:
19856055Srwatson			case ACL_GROUP:
19956055Srwatson				error = acl_name_to_id(t, qualifier, &id);
20056055Srwatson				if (error == -1)
20156055Srwatson					goto error_label;
20256055Srwatson				break;
20356055Srwatson
20456055Srwatson			default:
20556055Srwatson				errno = EINVAL;
20656055Srwatson				goto error_label;
20756055Srwatson			}
20856055Srwatson
20956055Srwatson			error = acl_add_entry(acl, t, id, p);
21056055Srwatson			if (error == -1)
21156055Srwatson				goto error_label;
21256055Srwatson		}
21356055Srwatson	}
21456055Srwatson
21556055Srwatson#if 0
21666259Srwatson	/* XXX Should we only return ACLs valid according to acl_valid? */
21766259Srwatson	/* Verify validity of the ACL we read in. */
21856055Srwatson	if (acl_valid(acl) == -1) {
21956055Srwatson		errno = EINVAL;
22056055Srwatson		goto error_label;
22156055Srwatson	}
22256055Srwatson#endif
22356055Srwatson
22456055Srwatson	return(acl);
22556055Srwatson
22656055Srwatsonerror_label:
22756055Srwatson	acl_free(acl);
22856055Srwatson	free(mybuf_p);
22956055Srwatson	return(0);
23056055Srwatson}
23156055Srwatson
23256055Srwatson
23356055Srwatson
234