add config_[set,get]() in util.c, replace ini-style config
[systembsd.git] / src / util.c
1 /*
2 * Copyright (c) 2014 Ian Sutton <ian@kremlin.cc>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <unistd.h>
18 #include <limits.h>
19 #include <string.h>
20
21 #include <glib/gprintf.h>
22 #include <glib-unix.h>
23 #include <polkit/polkit.h>
24
25 #include "util.h"
26
27 const gint MAX_TOKENS = 20;
28
29 /* return must be g_free()'d */
30 gchar *config_get(const gchar *path, gchar *key) {
31
32 gchar *content, **split_content, *cur, **cur_split, *ret;
33 GError *err;
34 int incr = 0;
35 gboolean breaker = TRUE;
36
37 ret = (gchar *) g_malloc0(4096);
38
39 if(!g_file_get_contents(path, &content, NULL, &err))
40 return NULL;
41
42 split_content = g_strsplit(content, "\n", MAX_TOKENS);
43
44 while(breaker && (cur = split_content[incr]) && (cur_split = g_strsplit(cur, "=", 2))) {
45
46 if(!g_strcmp0(key, cur_split[0])) {
47
48 g_strlcpy(ret, cur_split[1], 2048);
49 breaker = FALSE;
50 }
51
52 incr++;
53 g_strfreev(cur_split);
54 }
55
56 if(split_content)
57 g_strfreev(split_content);
58 if(content)
59 g_free(content);
60
61 return (ret ? ret : NULL);
62 }
63
64 gboolean config_set(const gchar *path, gchar *key, gchar *value) {
65
66 gchar *content, **split_content, *cur, **cur_split, *rewrite;
67 GError *err_set, *err_get;
68 gboolean ret = FALSE;
69 int incr = 0;
70 gboolean breaker = TRUE;
71
72 err_get = err_set = NULL;
73
74 if(!g_file_get_contents(path, &content, NULL, &err_get))
75 return FALSE;
76
77 split_content = g_strsplit(content, "\n", MAX_TOKENS);
78
79 while(breaker && (cur = split_content[incr]) && (cur_split = g_strsplit(cur, "=", 2))) {
80
81 if(!g_strcmp0(key, cur_split[0])) {
82
83 cur_split[1] = value;
84 split_content[incr] = g_strjoinv("=", cur_split);
85 ret = TRUE;
86 breaker = FALSE;
87 }
88
89 incr++;
90 }
91
92 if(ret) {
93
94 rewrite = g_strjoinv("\n", split_content);
95 ret = g_file_set_contents(path, rewrite, -1, &err_set);
96 g_free(rewrite);
97 }
98
99 if(cur_split)
100 g_strfreev(cur_split);
101 if(split_content)
102 g_strfreev(split_content);
103 if(content)
104 g_free(content);
105
106 return ret;
107 }
108
109 static gboolean is_valid_action(GList *action_list, const gchar *action) {
110
111 PolkitActionDescription *action_descr;
112 const gchar *action_descr_id;
113 GList *cur;
114 gboolean ret;
115
116 ret = FALSE;
117 cur = g_list_first(action_list);
118
119 while(cur && (action_descr = ((PolkitActionDescription *)(cur->data))) && (action_descr_id = polkit_action_description_get_action_id(action_descr))) {
120
121 if(!g_strcmp0(action, action_descr_id)) {
122 ret = TRUE;
123 break;
124 }
125
126 cur = cur->next;
127 }
128
129 g_list_free(action_list);
130
131 return ret;
132 }
133
134 check_auth_result polkit_try_auth(const gchar *bus, const gchar *action, gboolean prompt) {
135
136 GList *valid_actions;
137 PolkitAuthority *auth;
138 PolkitSubject *subj;
139 PolkitAuthorizationResult *result;
140 PolkitCheckAuthorizationFlags prompt_flag;
141 gboolean authorized, challenge;
142
143 auth = NULL;
144 subj = NULL;
145 result = NULL;
146 valid_actions = NULL;
147 authorized = challenge = FALSE;
148 prompt_flag = prompt ? POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION : POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE;
149
150 auth = polkit_authority_get_sync(NULL, NULL); /* TODO timeout for this */
151 subj = polkit_system_bus_name_new(bus);
152 valid_actions = polkit_authority_enumerate_actions_sync(auth, NULL, NULL);
153
154 if(!auth || !valid_actions)
155 return ERROR_GENERIC; /* extremely unlikely */
156 else if(!subj)
157 return ERROR_BADBUS;
158 else if(!is_valid_action(valid_actions, action))
159 return ERROR_BADACTION;
160
161 if(!(result = polkit_authority_check_authorization_sync(auth, subj, action, NULL, prompt_flag, NULL, NULL)))
162 return ERROR_GENERIC; /* TODO pass, check gerror and return more relevant error */
163
164 authorized = polkit_authorization_result_get_is_authorized(result);
165 challenge = polkit_authorization_result_get_is_challenge(result);
166
167 /* free()'s before return */
168 if(auth)
169 g_object_unref(auth);
170 if(subj)
171 g_object_unref(subj);
172 if(result)
173 g_object_unref(result);
174
175 if(authorized) {
176
177 if(challenge)
178 return AUTHORIZED_BY_PROMPT;
179
180 return AUTHORIZED_NATIVELY;
181
182 } else if(challenge)
183 return UNAUTHORIZED_FAILED_PROMPT;
184
185 return UNAUTHORIZED_NATIVELY;
186 }