Major manpage overhaul.
[usmb.git] / conffile.c
blob470f7d23ef38b6102e99c850be4c67ecbd95aa47
1 /* usmb - mount SMB shares via FUSE and Samba
2 * Copyright (C) 2006-2010 Geoff Johnstone
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "config.h"
18 #include <assert.h>
19 #include <errno.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <pwd.h>
27 #include <unistd.h>
28 #include "utils.h"
29 #include "xml.h"
30 #include "conffile.h"
31 #include "config.rng.h"
34 static bool check_conf_perms (const char *conffile, int fd)
36 struct stat buf;
38 if (0 == fstat (fd, &buf))
40 if (getuid() != buf.st_uid)
42 fprintf (stderr, "You do not own the configuration file %s.\n", conffile);
43 return false;
46 if (buf.st_mode & (S_IRWXG | S_IRWXO))
48 fprintf (stderr, "Configuration file %s is accessible to non-owner.\n",
49 conffile);
50 return false;
54 else
56 fprintf (stderr, "Cannot stat configuration file %s: %s.\n",
57 conffile, strerror (errno));
58 return false;
61 return true;
65 static bool conffile_read (const char *filename,
66 xmlDocPtr *doc,
67 xmlXPathContextPtr *ctx)
69 int fd = open (filename, O_RDONLY);
70 if (-1 == fd)
72 fprintf (stderr, "Cannot open %s: %s.\n", filename, strerror (errno));
73 return false;
76 if (!check_conf_perms (filename, fd))
78 (void)close (fd);
79 return false;
82 *doc = xmlReadFd (fd, NULL, NULL, XML_PARSE_NONET);
83 (void)close (fd);
85 if (NULL == *doc)
87 fprintf (stderr, "Cannot parse %s.\n", filename);
88 return false;
91 if (!xml_validate_relaxng (*doc, rng_config))
93 fprintf (stderr, "%s isn't a valid USMB configuration.\n", filename);
94 xmlFreeDoc (*doc);
95 return false;
98 *ctx = xmlXPathNewContext (*doc);
99 if (NULL == *ctx)
101 fputs ("Cannot create XPath context.\n", stderr);
102 xmlFreeDoc (*doc);
103 return false;
106 return true;
110 static bool do_xpath_text (xmlXPathContextPtr ctx,
111 const char *parent, const char *id,
112 const char *child, char **out)
114 char xpath[2048];
116 if (!bsnprintf (xpath, sizeof (xpath),
117 "/usmbconfig/%s[@id='%s']/%s/text()", parent, id, child))
118 return false;
120 return xml_xpath_text (ctx, xpath, (void *)out);
124 // Expand ~ in *mountpoint.
125 static bool expand_tilde (char **mountpoint)
127 assert (NULL != mountpoint);
128 assert (NULL != *mountpoint);
130 if ('~' != **mountpoint)
131 return true;
133 // Extract the username.
134 char * const username = (*mountpoint) + 1;
135 char * const end = strchr (username, '/');
137 const char *dir = NULL;
139 if (('\0' == *username) || (end == username)) // No username => use HOME.
141 dir = getenv ("HOME");
143 else // Else look up the user's home directory.
145 if (NULL != end)
146 *end = '\0';
148 struct passwd * const pwd = getpwnam (username);
149 if (NULL != pwd)
150 dir = pwd->pw_dir;
152 if (NULL != end)
153 *end = '/';
156 if (NULL == dir)
158 fputs ("Failed to expand tilde in mount point.\n", stderr);
159 return false;
162 char *result;
163 if (!baprintf (&result, "%s%s", dir, (NULL == end) ? "" : end))
165 perror ("Failed to expand tilde in mount point");
166 return false;
169 free (*mountpoint);
170 *mountpoint = result;
171 return true;
175 bool conffile_get_mount (const char *filename, const char *key,
176 char **server, char **share,
177 char **mountpoint, char **options,
178 char **domain, char **username,
179 char **password)
181 xmlDocPtr doc;
182 xmlXPathContextPtr ctx;
183 char xp[2048];
184 char *creds = NULL;
186 *server = *share = *mountpoint = *options = NULL;
187 *domain = *username = *password = NULL;
189 if (strchr (key, '\''))
191 fprintf (stderr, "Invalid share name: %s.\n", key);
192 return false;
195 if (!conffile_read (filename, &doc, &ctx))
196 return false;
198 do {
199 if (!do_xpath_text (ctx, "mount", key, "server", server)) break;
200 if (!do_xpath_text (ctx, "mount", key, "share", share)) break;
201 if (!do_xpath_text (ctx, "mount", key, "mountpoint", mountpoint)) break;
202 if (!expand_tilde (mountpoint)) break;
203 (void)do_xpath_text (ctx, "mount", key, "options", options);
205 if (!snprintf (xp, sizeof (xp), "/usmbconfig/mount[@id='%s']", key)) break;
206 if (!xml_xpath_attr_value (ctx, xp, "credentials", &creds)) break;
208 (void)do_xpath_text (ctx, "credentials", creds, "domain", domain);
209 if (!do_xpath_text (ctx, "credentials", creds, "username", username)) break;
211 if (!do_xpath_text (ctx, "credentials", creds, "password", password))
212 *password = NULL;
214 xmlXPathFreeContext (ctx);
215 xmlFreeDoc (doc);
217 return true;
218 /*NOTREACHED*/
219 } while (false /*CONSTCOND*/);
221 fputs ("Invalid configuration.\n", stderr);
223 xfree (*username);
224 clear_and_free (*password);
225 xfree (*domain);
226 xfree (creds);
227 xfree (*options);
228 xfree (*mountpoint);
229 xfree (*share);
230 xfree (*server);
232 xmlXPathFreeContext (ctx);
233 xmlFreeDoc (doc);
235 return false;