acl_from_text.c revision 56055
156055Srwatson/*-
256055Srwatson * Copyright (c) 1999 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 *	$FreeBSD: head/lib/libc/posix1e/acl_from_text.c 56055 2000-01-15 19:44:27Z rwatson $
2756055Srwatson */
2856055Srwatson/*
2956055Srwatson * 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
4156055Srwatsonenum PARSE_MODE {
4256055Srwatson	PM_BASE,		/* initial, begin line, or after , */
4356055Srwatson	PM_QUALIFIER,		/* in qualifier field */
4456055Srwatson	PM_PERM,		/* in permission field */
4556055Srwatson	PM_COMMENT,		/* in comment */
4656055Srwatson};
4756055Srwatson
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
8056055Srwatsonacl_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/*
11056055Srwatson * acl_from_text -- convert a string into an ACL
11156055Srwatson * postpone most validity checking until the end and cal acl_valid to do
11256055Srwatson * that.
11356055Srwatson */
11456055Srwatsonacl_t
11556055Srwatsonacl_from_text(const char *buf_p)
11656055Srwatson{
11756055Srwatson	acl_tag_t	t;
11856055Srwatson	acl_perm_t	p;
11956055Srwatson	acl_t	acl;
12056055Srwatson	uid_t	id;
12156055Srwatson	char	*mybuf_p, *line, *cur, *notcomment, *comment, *entry;
12256055Srwatson	char	*tag, *qualifier, *permission;
12356055Srwatson	int	error;
12456055Srwatson
12556055Srwatson	/* local copy we can mess up */
12656055Srwatson	mybuf_p = strdup(buf_p);
12756055Srwatson	if (!mybuf_p) {
12856055Srwatson		errno = ENOMEM;
12956055Srwatson		return(0);
13056055Srwatson	}
13156055Srwatson
13256055Srwatson	acl = acl_init(3);
13356055Srwatson	if (!acl) {
13456055Srwatson		free(mybuf_p);
13556055Srwatson		errno = ENOMEM;
13656055Srwatson		return(0);
13756055Srwatson	}
13856055Srwatson
13956055Srwatson	/* outer loop: delimit at \n boundaries */
14056055Srwatson	cur = mybuf_p;
14156055Srwatson	while ((line = strsep(&cur, "\n"))) {
14256055Srwatson		/* now split the line on the first # to strip out comments */
14356055Srwatson		comment = line;
14456055Srwatson		notcomment = strsep(&comment, "#");
14556055Srwatson
14656055Srwatson		/* inner loop: delimit at , boundaries */
14756055Srwatson		while ((entry = strsep(&notcomment, ","))) {
14856055Srwatson			/* now split into three :-delimited fields */
14956055Srwatson			tag = strsep(&entry, ":");
15056055Srwatson			if (!tag) {
15156055Srwatson				/* printf("no tag\n"); */
15256055Srwatson				errno = EINVAL;
15356055Srwatson				goto error_label;
15456055Srwatson			}
15556055Srwatson			tag = string_skip_whitespace(tag);
15656055Srwatson			if ((*tag == '\0') && (!entry)) {
15756055Srwatson				/*
15856055Srwatson				 * is an entirely comment line, skip to next
15956055Srwatson				 * comma
16056055Srwatson				 */
16156055Srwatson				continue;
16256055Srwatson			}
16356055Srwatson			string_trim_trailing_whitespace(tag);
16456055Srwatson
16556055Srwatson			qualifier = strsep(&entry, ":");
16656055Srwatson			if (!qualifier) {
16756055Srwatson				/* printf("no qualifier\n"); */
16856055Srwatson				errno = EINVAL;
16956055Srwatson				goto error_label;
17056055Srwatson			}
17156055Srwatson			qualifier = string_skip_whitespace(qualifier);
17256055Srwatson			string_trim_trailing_whitespace(qualifier);
17356055Srwatson
17456055Srwatson			permission = strsep(&entry, ":");
17556055Srwatson			if ((!permission) || (entry)) {
17656055Srwatson				/* printf("no permission, or more stuff\n"); */
17756055Srwatson				errno = EINVAL;
17856055Srwatson				goto error_label;
17956055Srwatson			}
18056055Srwatson			permission = string_skip_whitespace(permission);
18156055Srwatson			string_trim_trailing_whitespace(permission);
18256055Srwatson
18356055Srwatson			/* printf("[%s/%s/%s]\n", tag, qualifier,
18456055Srwatson			    permission); */
18556055Srwatson
18656055Srwatson			t = acl_string_to_tag(tag, qualifier);
18756055Srwatson			if (t == -1) {
18856055Srwatson				errno = EINVAL;
18956055Srwatson				goto error_label;
19056055Srwatson			}
19156055Srwatson
19256055Srwatson			error = acl_string_to_perm(permission, &p);
19356055Srwatson			if (error == -1) {
19456055Srwatson				errno = EINVAL;
19556055Srwatson				goto error_label;
19656055Srwatson			}
19756055Srwatson
19856055Srwatson			switch(t) {
19956055Srwatson			case ACL_USER_OBJ:
20056055Srwatson			case ACL_GROUP_OBJ:
20156055Srwatson			case ACL_MASK:
20256055Srwatson			case ACL_OTHER:
20356055Srwatson				if (*qualifier != '\0') {
20456055Srwatson					errno = EINVAL;
20556055Srwatson					goto error_label;
20656055Srwatson				}
20756055Srwatson				id = 0;
20856055Srwatson				break;
20956055Srwatson
21056055Srwatson			case ACL_USER:
21156055Srwatson			case ACL_GROUP:
21256055Srwatson				error = acl_name_to_id(t, qualifier, &id);
21356055Srwatson				if (error == -1)
21456055Srwatson					goto error_label;
21556055Srwatson				break;
21656055Srwatson
21756055Srwatson			default:
21856055Srwatson				errno = EINVAL;
21956055Srwatson				goto error_label;
22056055Srwatson			}
22156055Srwatson
22256055Srwatson			error = acl_add_entry(acl, t, id, p);
22356055Srwatson			if (error == -1)
22456055Srwatson				goto error_label;
22556055Srwatson		}
22656055Srwatson	}
22756055Srwatson
22856055Srwatson#if 0
22956055Srwatson	/* XXX should we only return ACLs valid according to acl_valid? */
23056055Srwatson	/* verify validity of the ACL we read in */
23156055Srwatson	if (acl_valid(acl) == -1) {
23256055Srwatson		errno = EINVAL;
23356055Srwatson		goto error_label;
23456055Srwatson	}
23556055Srwatson#endif
23656055Srwatson
23756055Srwatson	return(acl);
23856055Srwatson
23956055Srwatsonerror_label:
24056055Srwatson	acl_free(acl);
24156055Srwatson	free(mybuf_p);
24256055Srwatson	return(0);
24356055Srwatson}
24456055Srwatson
24556055Srwatson
24656055Srwatson
247