Line data Source code
1 : /*
2 : SSSD
3 :
4 : sss_groupmod
5 :
6 : Copyright (C) Jakub Hrozek <jhrozek@redhat.com> 2009
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include <stdio.h>
23 : #include <stdlib.h>
24 : #include <talloc.h>
25 : #include <popt.h>
26 : #include <errno.h>
27 : #include <grp.h>
28 : #include <unistd.h>
29 :
30 : #include "util/util.h"
31 : #include "db/sysdb.h"
32 : #include "tools/tools_util.h"
33 : #include "tools/sss_sync_ops.h"
34 :
35 0 : int main(int argc, const char **argv)
36 : {
37 0 : gid_t pc_gid = 0;
38 0 : int pc_debug = SSSDBG_DEFAULT;
39 0 : struct poptOption long_options[] = {
40 : POPT_AUTOHELP
41 : { "debug", '\0', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &pc_debug,
42 0 : 0, _("The debug level to run with"), NULL },
43 : { "append-group", 'a', POPT_ARG_STRING, NULL,
44 0 : 'a', _("Groups to add this group to"), NULL },
45 : { "remove-group", 'r', POPT_ARG_STRING, NULL,
46 0 : 'r', _("Groups to remove this group from"), NULL },
47 : { "gid", 'g', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &pc_gid,
48 0 : 0, _("The GID of the group"), NULL },
49 : POPT_TABLEEND
50 : };
51 0 : poptContext pc = NULL;
52 0 : struct tools_ctx *tctx = NULL;
53 0 : char *addgroups = NULL, *rmgroups = NULL;
54 : int ret;
55 : errno_t sret;
56 0 : const char *pc_groupname = NULL;
57 0 : char *badgroup = NULL;
58 0 : bool in_transaction = false;
59 :
60 0 : debug_prg_name = argv[0];
61 :
62 0 : ret = set_locale();
63 0 : if (ret != EOK) {
64 0 : DEBUG(SSSDBG_CRIT_FAILURE,
65 : "set_locale failed (%d): %s\n", ret, strerror(ret));
66 0 : ERROR("Error setting the locale\n");
67 0 : ret = EXIT_FAILURE;
68 0 : goto fini;
69 : }
70 :
71 : /* parse parameters */
72 0 : pc = poptGetContext(NULL, argc, argv, long_options, 0);
73 0 : poptSetOtherOptionHelp(pc, "GROUPNAME");
74 0 : while ((ret = poptGetNextOpt(pc)) > 0) {
75 0 : switch (ret) {
76 : case 'a':
77 0 : addgroups = poptGetOptArg(pc);
78 0 : if (addgroups == NULL) {
79 0 : BAD_POPT_PARAMS(pc, _("Specify group to add to\n"),
80 : ret, fini);
81 : }
82 0 : break;
83 :
84 : case 'r':
85 0 : rmgroups = poptGetOptArg(pc);
86 0 : if (rmgroups == NULL) {
87 0 : BAD_POPT_PARAMS(pc, _("Specify group to remove from\n"),
88 : ret, fini);
89 : }
90 0 : break;
91 : }
92 : }
93 :
94 0 : if (ret != -1) {
95 0 : BAD_POPT_PARAMS(pc, poptStrerror(ret), ret, fini);
96 : }
97 :
98 : /* groupname is an argument without --option */
99 0 : pc_groupname = poptGetArg(pc);
100 0 : if (pc_groupname == NULL) {
101 0 : BAD_POPT_PARAMS(pc, _("Specify group to modify\n"), ret, fini);
102 : }
103 :
104 0 : DEBUG_CLI_INIT(pc_debug);
105 :
106 0 : CHECK_ROOT(ret, debug_prg_name);
107 :
108 0 : ret = init_sss_tools(&tctx);
109 0 : if (ret != EOK) {
110 0 : DEBUG(SSSDBG_CRIT_FAILURE,
111 : "init_sss_tools failed (%d): %s\n", ret, strerror(ret));
112 0 : if (ret == ENOENT) {
113 0 : ERROR("Error initializing the tools - no local domain\n");
114 : } else {
115 0 : ERROR("Error initializing the tools\n");
116 : }
117 0 : ret = EXIT_FAILURE;
118 0 : goto fini;
119 : }
120 :
121 0 : ret = parse_name_domain(tctx, pc_groupname);
122 0 : if (ret != EOK) {
123 0 : ERROR("Invalid domain specified in FQDN\n");
124 0 : ret = EXIT_FAILURE;
125 0 : goto fini;
126 : }
127 : /* check the username to be able to give sensible error message */
128 0 : ret = sysdb_getgrnam_sync(tctx, tctx->octx->name, tctx->octx);
129 0 : if (ret != EOK) {
130 0 : ERROR("Cannot find group in local domain, "
131 : "modifying groups is allowed only in local domain\n");
132 0 : ret = EXIT_FAILURE;
133 0 : goto fini;
134 : }
135 :
136 :
137 0 : tctx->octx->gid = pc_gid;
138 :
139 0 : if (addgroups) {
140 0 : ret = parse_groups(tctx, addgroups, &tctx->octx->addgroups);
141 0 : if (ret != EOK) {
142 0 : DEBUG(SSSDBG_CRIT_FAILURE,
143 : "Cannot parse groups to add the group to\n");
144 0 : ERROR("Internal error while parsing parameters\n");
145 0 : ret = EXIT_FAILURE;
146 0 : goto fini;
147 : }
148 :
149 0 : ret = parse_group_name_domain(tctx, tctx->octx->addgroups);
150 0 : if (ret != EOK) {
151 0 : DEBUG(SSSDBG_CRIT_FAILURE,
152 : "Cannot parse FQDN groups to add the group to\n");
153 0 : ERROR("Member groups must be in the same domain as parent group\n");
154 0 : ret = EXIT_FAILURE;
155 0 : goto fini;
156 : }
157 :
158 : /* Check group names in the LOCAL domain */
159 0 : ret = check_group_names(tctx, tctx->octx->addgroups, &badgroup);
160 0 : if (ret != EOK) {
161 0 : ERROR("Cannot find group %1$s in local domain, "
162 : "only groups in local domain are allowed\n", badgroup);
163 0 : ret = EXIT_FAILURE;
164 0 : goto fini;
165 : }
166 : }
167 :
168 0 : if (rmgroups) {
169 0 : ret = parse_groups(tctx, rmgroups, &tctx->octx->rmgroups);
170 0 : if (ret != EOK) {
171 0 : DEBUG(SSSDBG_CRIT_FAILURE,
172 : "Cannot parse groups to remove the group from\n");
173 0 : ERROR("Internal error while parsing parameters\n");
174 0 : ret = EXIT_FAILURE;
175 0 : goto fini;
176 : }
177 :
178 0 : ret = parse_group_name_domain(tctx, tctx->octx->rmgroups);
179 0 : if (ret != EOK) {
180 0 : DEBUG(SSSDBG_CRIT_FAILURE,
181 : "Cannot parse FQDN groups to remove the group from\n");
182 0 : ERROR("Member groups must be in the same domain as parent group\n");
183 0 : ret = EXIT_FAILURE;
184 0 : goto fini;
185 : }
186 :
187 : /* Check group names in the LOCAL domain */
188 0 : ret = check_group_names(tctx, tctx->octx->rmgroups, &badgroup);
189 0 : if (ret != EOK) {
190 0 : ERROR("Cannot find group %1$s in local domain, "
191 : "only groups in local domain are allowed\n", badgroup);
192 0 : ret = EXIT_FAILURE;
193 0 : goto fini;
194 : }
195 : }
196 :
197 0 : if (id_in_range(tctx->octx->gid, tctx->octx->domain) != EOK) {
198 0 : ERROR("The selected GID is outside the allowed range\n");
199 0 : ret = EXIT_FAILURE;
200 0 : goto fini;
201 : }
202 :
203 0 : tctx->error = sysdb_transaction_start(tctx->sysdb);
204 0 : if (tctx->error != EOK) {
205 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
206 0 : goto done;
207 : }
208 0 : in_transaction = true;
209 :
210 : /* groupmod */
211 0 : tctx->error = groupmod(tctx, tctx->octx);
212 0 : if (tctx->error) {
213 0 : goto done;
214 : }
215 :
216 0 : tctx->error = sysdb_transaction_commit(tctx->sysdb);
217 0 : if (tctx->error != EOK) {
218 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
219 0 : goto done;
220 : }
221 0 : in_transaction = false;
222 :
223 0 : ret = sss_mc_refresh_group(pc_groupname);
224 0 : if (ret != EOK) {
225 0 : ERROR("NSS request failed (%1$d). Entry might remain in memory "
226 : "cache.\n", ret);
227 : /* Nothing we can do about it */
228 : }
229 :
230 0 : ret = sss_mc_refresh_grouplist(tctx, tctx->octx->addgroups);
231 0 : if (ret != EOK) {
232 0 : ERROR("NSS request failed (%1$d). Entry might remain in memory "
233 : "cache.\n", ret);
234 : /* Nothing we can do about it */
235 : }
236 :
237 0 : ret = sss_mc_refresh_grouplist(tctx, tctx->octx->rmgroups);
238 0 : if (ret != EOK) {
239 0 : ERROR("NSS request failed (%1$d). Entry might remain in memory "
240 : "cache.\n", ret);
241 : /* Nothing we can do about it */
242 : }
243 :
244 : done:
245 0 : if (in_transaction) {
246 0 : sret = sysdb_transaction_cancel(tctx->sysdb);
247 0 : if (sret != EOK) {
248 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
249 : }
250 : }
251 0 : if (tctx->error) {
252 0 : ret = tctx->error;
253 0 : DEBUG(SSSDBG_CRIT_FAILURE,
254 : "sysdb operation failed (%d)[%s]\n", ret, strerror(ret));
255 0 : switch (ret) {
256 : case ENOENT:
257 0 : ERROR("Could not modify group - check if member group names are correct\n");
258 0 : break;
259 :
260 : case EFAULT:
261 0 : ERROR("Could not modify group - check if groupname is correct\n");
262 0 : break;
263 :
264 : default:
265 0 : ERROR("Transaction error. Could not modify group.\n");
266 0 : break;
267 : }
268 :
269 0 : ret = EXIT_FAILURE;
270 0 : goto fini;
271 : }
272 :
273 0 : ret = EXIT_SUCCESS;
274 :
275 : fini:
276 0 : free(addgroups);
277 0 : free(rmgroups);
278 0 : poptFreeContext(pc);
279 0 : talloc_free(tctx);
280 0 : exit(ret);
281 : }
|