1236099Sdes/*-
2236099Sdes * Copyright (c) 2011 Dag-Erling Sm��rgrav
3236099Sdes * All rights reserved.
4236099Sdes *
5236099Sdes * Redistribution and use in source and binary forms, with or without
6236099Sdes * modification, are permitted provided that the following conditions
7236099Sdes * are met:
8236099Sdes * 1. Redistributions of source code must retain the above copyright
9255376Sdes *    notice, this list of conditions and the following disclaimer.
10236099Sdes * 2. Redistributions in binary form must reproduce the above copyright
11236099Sdes *    notice, this list of conditions and the following disclaimer in the
12236099Sdes *    documentation and/or other materials provided with the distribution.
13236099Sdes * 3. The name of the author may not be used to endorse or promote
14236099Sdes *    products derived from this software without specific prior written
15236099Sdes *    permission.
16236099Sdes *
17236099Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18236099Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19236099Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20236099Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21236099Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22236099Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23236099Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24236099Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25236099Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26236099Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27236099Sdes * SUCH DAMAGE.
28236099Sdes *
29271947Sdes * $Id: openpam_dump_policy.c 798 2014-06-10 21:28:14Z des $
30236099Sdes */
31236099Sdes
32236099Sdes#ifdef HAVE_CONFIG_H
33236099Sdes# include "config.h"
34236099Sdes#endif
35236099Sdes
36236099Sdes#include <ctype.h>
37236099Sdes#include <stdio.h>
38236099Sdes#include <stdlib.h>
39236099Sdes#include <string.h>
40236099Sdes#include <unistd.h>
41236099Sdes
42236099Sdes#include <security/pam_appl.h>
43236099Sdes
44236099Sdes#include "openpam_impl.h"
45255376Sdes#include "openpam_asprintf.h"
46236099Sdes
47236099Sdesstatic char *
48236099Sdesopenpam_chain_name(const char *service, pam_facility_t fclt)
49236099Sdes{
50236099Sdes	const char *facility = pam_facility_name[fclt];
51236099Sdes	char *name;
52236099Sdes
53236099Sdes	if (asprintf(&name, "pam_%s_%s", service, facility) == -1)
54236099Sdes		return (NULL);
55236099Sdes	return (name);
56236099Sdes}
57236099Sdes
58236099Sdesstatic char *
59236099Sdesopenpam_facility_index_name(pam_facility_t fclt)
60236099Sdes{
61236099Sdes	const char *facility = pam_facility_name[fclt];
62236099Sdes	char *name, *p;
63236099Sdes
64236099Sdes	if (asprintf(&name, "PAM_%s", facility) == -1)
65236099Sdes		return (NULL);
66236099Sdes	for (p = name + 4; *p; ++p)
67271947Sdes		*p = toupper((unsigned char)*p);
68236099Sdes	return (name);
69236099Sdes}
70236099Sdes
71236099Sdesint
72236099Sdesopenpam_dump_chain(const char *name, pam_chain_t *chain)
73236099Sdes{
74236099Sdes	char *modname, **opt, *p;
75236099Sdes	int i;
76236099Sdes
77236099Sdes	for (i = 0; chain != NULL; ++i, chain = chain->next) {
78236099Sdes		/* declare the module's struct pam_module */
79236099Sdes		modname = strrchr(chain->module->path, '/');
80236099Sdes		modname = strdup(modname ? modname : chain->module->path);
81236099Sdes		if (modname == NULL)
82236099Sdes			return (PAM_BUF_ERR);
83236099Sdes		for (p = modname; *p && *p != '.'; ++p)
84236099Sdes			/* nothing */ ;
85236099Sdes		*p = '\0';
86236099Sdes		printf("extern struct pam_module %s_pam_module;\n", modname);
87236099Sdes		/* module arguments */
88236099Sdes		printf("static char *%s_%d_optv[] = {\n", name, i);
89236099Sdes		for (opt = chain->optv; *opt; ++opt) {
90236099Sdes			printf("\t\"");
91236099Sdes			for (p = *opt; *p; ++p) {
92236099Sdes				if (isprint((unsigned char)*p) && *p != '"')
93236099Sdes					printf("%c", *p);
94236099Sdes				else
95236099Sdes					printf("\\x%02x", (unsigned char)*p);
96236099Sdes			}
97236099Sdes			printf("\",\n");
98236099Sdes		}
99236099Sdes		printf("\tNULL,\n");
100236099Sdes		printf("};\n");
101236099Sdes		/* next module in chain */
102236099Sdes		if (chain->next != NULL)
103236099Sdes			printf("static pam_chain_t %s_%d;\n", name, i + 1);
104236099Sdes		/* chain entry */
105236099Sdes		printf("static pam_chain_t %s_%d = {\n", name, i);
106236099Sdes		printf("\t.module = &%s_pam_module,\n", modname);
107236099Sdes		printf("\t.flag = 0x%08x,\n", chain->flag);
108236099Sdes		printf("\t.optc = %d,\n", chain->optc);
109236099Sdes		printf("\t.optv = %s_%d_optv,\n", name, i);
110236099Sdes		if (chain->next)
111236099Sdes			printf("\t.next = &%s_%d,\n", name, i + 1);
112236099Sdes		else
113236099Sdes			printf("\t.next = NULL,\n");
114236099Sdes		printf("};\n");
115236099Sdes		free(modname);
116236099Sdes	}
117236099Sdes	return (PAM_SUCCESS);
118236099Sdes}
119236099Sdes
120236099Sdesint
121236099Sdesopenpam_dump_policy(const char *service)
122236099Sdes{
123236099Sdes	pam_handle_t *pamh;
124236099Sdes	char *name;
125236099Sdes	int fclt, ret;
126236099Sdes
127236099Sdes	if ((pamh = calloc(1, sizeof *pamh)) == NULL)
128236099Sdes		return (PAM_BUF_ERR);
129236099Sdes	if ((ret = openpam_configure(pamh, service)) != PAM_SUCCESS)
130236099Sdes		return (ret);
131236099Sdes	for (fclt = 0; fclt < PAM_NUM_FACILITIES; ++fclt) {
132236099Sdes		if (pamh->chains[fclt] != NULL) {
133236099Sdes			if ((name = openpam_chain_name(service, fclt)) == NULL)
134236099Sdes				return (PAM_BUF_ERR);
135236099Sdes			ret = openpam_dump_chain(name, pamh->chains[fclt]);
136236099Sdes			free(name);
137236099Sdes			if (ret != PAM_SUCCESS)
138236099Sdes				return (ret);
139236099Sdes		}
140236099Sdes	}
141236099Sdes	printf("static pam_policy_t pam_%s_policy = {\n", service);
142236099Sdes	printf("\t.service = \"%s\",\n", service);
143236099Sdes	printf("\t.chains = {\n");
144236099Sdes	for (fclt = 0; fclt < PAM_NUM_FACILITIES; ++fclt) {
145236099Sdes		if ((name = openpam_facility_index_name(fclt)) == NULL)
146236099Sdes			return (PAM_BUF_ERR);
147236099Sdes		printf("\t\t[%s] = ", name);
148236099Sdes		free(name);
149236099Sdes		if (pamh->chains[fclt] != NULL) {
150236099Sdes			if ((name = openpam_chain_name(service, fclt)) == NULL)
151236099Sdes				return (PAM_BUF_ERR);
152236099Sdes			printf("&%s_0,\n", name);
153236099Sdes			free(name);
154236099Sdes		} else {
155236099Sdes			printf("NULL,\n");
156236099Sdes		}
157236099Sdes	}
158236099Sdes	printf("\t},\n");
159236099Sdes	printf("};\n");
160236099Sdes	free(pamh);
161236099Sdes	return (PAM_SUCCESS);
162236099Sdes}
163236099Sdes
164236099Sdesstatic void
165236099Sdesusage(void)
166236099Sdes{
167236099Sdes
168236099Sdes	fprintf(stderr, "usage: openpam_dump_policy [-d] policy ...\n");
169236099Sdes	exit(1);
170236099Sdes}
171236099Sdes
172236099Sdesint
173236099Sdesmain(int argc, char *argv[])
174236099Sdes{
175236099Sdes	int i, opt;
176236099Sdes
177236099Sdes	while ((opt = getopt(argc, argv, "d")) != -1)
178236099Sdes		switch (opt) {
179236099Sdes		case 'd':
180236099Sdes			openpam_debug = 1;
181236099Sdes			break;
182236099Sdes		default:
183236099Sdes			usage();
184236099Sdes		}
185236099Sdes
186236099Sdes	argc -= optind;
187236099Sdes	argv += optind;
188236099Sdes
189236099Sdes	if (argc < 1)
190236099Sdes		usage();
191236099Sdes
192236099Sdes	printf("#include <security/pam_appl.h>\n");
193236099Sdes	printf("#include \"openpam_impl.h\"\n");
194236099Sdes	for (i = 0; i < argc; ++i)
195236099Sdes		openpam_dump_policy(argv[i]);
196236099Sdes	printf("pam_policy_t *pam_embedded_policies[] = {\n");
197236099Sdes	for (i = 0; i < argc; ++i)
198236099Sdes		printf("\t&pam_%s_policy,\n", argv[i]);
199236099Sdes	printf("\tNULL,\n");
200236099Sdes	printf("};\n");
201236099Sdes	exit(0);
202236099Sdes}
203