r16945: Sync trunk -> 3.0 for 3.0.24 code. Still need
[metze/samba/wip.git] / source3 / utils / net_idmap.c
1 /* 
2    Samba Unix/Linux SMB client library 
3    Distributed SMB/CIFS Server Management Utility 
4    Copyright (C) 2003 Andrew Bartlett (abartlet@samba.org)
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 #include "includes.h"
21 #include "utils/net.h"
22
23
24 /***********************************************************
25  Helper function for net_idmap_dump. Dump one entry.
26  **********************************************************/
27 static int net_idmap_dump_one_entry(TDB_CONTEXT *tdb,
28                                     TDB_DATA key,
29                                     TDB_DATA data,
30                                     void *unused)
31 {
32         if (strcmp(key.dptr, "USER HWM") == 0) {
33                 printf("USER HWM %d\n", IVAL(data.dptr,0));
34                 return 0;
35         }
36
37         if (strcmp(key.dptr, "GROUP HWM") == 0) {
38                 printf("GROUP HWM %d\n", IVAL(data.dptr,0));
39                 return 0;
40         }
41
42         if (strncmp(key.dptr, "S-", 2) != 0)
43                 return 0;
44
45         printf("%s %s\n", data.dptr, key.dptr);
46         return 0;
47 }
48
49 /***********************************************************
50  Dump the current idmap
51  **********************************************************/
52 static int net_idmap_dump(int argc, const char **argv)
53 {
54         TDB_CONTEXT *idmap_tdb;
55
56         if ( argc != 1 )
57                 return net_help_idmap( argc, argv );
58
59         idmap_tdb = tdb_open_log(argv[0], 0, TDB_DEFAULT, O_RDONLY, 0);
60
61         if (idmap_tdb == NULL) {
62                 d_fprintf(stderr, "Could not open idmap: %s\n", argv[0]);
63                 return -1;
64         }
65
66         tdb_traverse(idmap_tdb, net_idmap_dump_one_entry, NULL);
67
68         tdb_close(idmap_tdb);
69
70         return 0;
71 }
72
73 /***********************************************************
74  Fix up the HWMs after a idmap restore.
75  **********************************************************/
76
77 struct hwms {
78         BOOL ok;
79         uid_t user_hwm;
80         gid_t group_hwm;
81 };
82
83 static int net_idmap_find_max_id(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA data,
84                                  void *handle)
85 {
86         struct hwms *hwms = (struct hwms *)handle;
87         void *idptr = NULL;
88         BOOL isgid = False;
89         int id;
90
91         if (strncmp(key.dptr, "S-", 2) != 0)
92                 return 0;
93
94         if (sscanf(data.dptr, "GID %d", &id) == 1) {
95                 idptr = (void *)&hwms->group_hwm;
96                 isgid = True;
97         }
98
99         if (sscanf(data.dptr, "UID %d", &id) == 1) {
100                 idptr = (void *)&hwms->user_hwm;
101                 isgid = False;
102         }
103
104         if (idptr == NULL) {
105                 d_fprintf(stderr, "Illegal idmap entry: [%s]->[%s]\n",
106                          key.dptr, data.dptr);
107                 hwms->ok = False;
108                 return -1;
109         }
110
111         if (isgid) {
112                 if (hwms->group_hwm <= (gid_t)id) {
113                         hwms->group_hwm = (gid_t)(id+1);
114                 }
115         } else {
116                 if (hwms->user_hwm <= (uid_t)id) {
117                         hwms->user_hwm = (uid_t)(id+1);
118                 }
119         }
120
121         return 0;
122 }
123
124 static NTSTATUS net_idmap_fixup_hwm(void)
125 {
126         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
127         TDB_CONTEXT *idmap_tdb;
128         char *tdbfile = NULL;
129
130         struct hwms hwms;
131         struct hwms highest;
132
133         if (!lp_idmap_uid(&hwms.user_hwm, &highest.user_hwm) ||
134             !lp_idmap_gid(&hwms.group_hwm, &highest.group_hwm)) {
135                 d_fprintf(stderr, "idmap range missing\n");
136                 return NT_STATUS_UNSUCCESSFUL;
137         }
138
139         tdbfile = SMB_STRDUP(lock_path("winbindd_idmap.tdb"));
140         if (!tdbfile) {
141                 DEBUG(0, ("idmap_init: out of memory!\n"));
142                 return NT_STATUS_NO_MEMORY;
143         }
144
145         idmap_tdb = tdb_open_log(tdbfile, 0, TDB_DEFAULT, O_RDWR, 0);
146
147         if (idmap_tdb == NULL) {
148                 d_fprintf(stderr, "Could not open idmap: %s\n", tdbfile);
149                 return NT_STATUS_NO_SUCH_FILE;
150         }
151
152         hwms.ok = True;
153
154         tdb_traverse(idmap_tdb, net_idmap_find_max_id, &hwms);
155
156         if (!hwms.ok) {
157                 goto done;
158         }
159
160         d_printf("USER HWM: %d  GROUP HWM: %d\n",
161                  hwms.user_hwm, hwms.group_hwm);
162
163         if (hwms.user_hwm >= highest.user_hwm) {
164                 d_fprintf(stderr, "Highest UID out of uid range\n");
165                 goto done;
166         }
167
168         if (hwms.group_hwm >= highest.group_hwm) {
169                 d_fprintf(stderr, "Highest GID out of gid range\n");
170                 goto done;
171         }
172
173         if ((tdb_store_int32(idmap_tdb, "USER HWM", (int32)hwms.user_hwm) != 0) ||
174             (tdb_store_int32(idmap_tdb, "GROUP HWM", (int32)hwms.group_hwm) != 0)) {
175                 d_fprintf(stderr, "Could not store HWMs\n");
176                 goto done;
177         }
178
179         result = NT_STATUS_OK;
180  done:
181         tdb_close(idmap_tdb);
182         return result;
183 }
184
185 /***********************************************************
186  Write entries from stdin to current local idmap
187  **********************************************************/
188
189 static int net_idmap_restore(int argc, const char **argv)
190 {
191         if (!idmap_init(lp_idmap_backend())) {
192                 d_fprintf(stderr, "Could not init idmap\n");
193                 return -1;
194         }
195
196         while (!feof(stdin)) {
197                 fstring line, sid_string, fmt_string1, fmt_string2;
198                 int len;
199                 unid_t id;
200                 enum idmap_type type;
201                 unsigned long idval;
202                 DOM_SID sid;
203
204                 if (fgets(line, sizeof(line)-1, stdin) == NULL)
205                         break;
206
207                 len = strlen(line);
208
209                 if ( (len > 0) && (line[len-1] == '\n') )
210                         line[len-1] = '\0';
211
212                 snprintf(fmt_string1, sizeof(fmt_string1), "GID %%ul %%%us", FSTRING_LEN);
213                 snprintf(fmt_string2, sizeof(fmt_string2), "UID %%ul %%%us", FSTRING_LEN);
214
215                 if (sscanf(line, fmt_string1, &idval, sid_string) == 2) {
216                         type = ID_GROUPID;
217                         id.gid = (gid_t)idval;
218                 } else if (sscanf(line, fmt_string2, &idval, sid_string) == 2) {
219                         type = ID_USERID;
220                         id.uid = (uid_t)idval;
221                 } else {
222                         d_printf("ignoring invalid line [%s]\n", line);
223                         continue;
224                 }
225
226                 if (!string_to_sid(&sid, sid_string)) {
227                         d_printf("ignoring invalid sid [%s]\n", sid_string);
228                         continue;
229                 }
230
231                 if (!NT_STATUS_IS_OK(idmap_set_mapping(&sid, id, type))) {
232                         d_fprintf(stderr, "Could not set mapping of %s %lu to sid %s\n",
233                                  (type == ID_GROUPID) ? "GID" : "UID",
234                                  (type == ID_GROUPID) ? (unsigned long)id.gid:
235                                  (unsigned long)id.uid, 
236                                  sid_string_static(&sid));
237                         continue;
238                 }
239                                  
240         }
241
242         idmap_close();
243
244         return NT_STATUS_IS_OK(net_idmap_fixup_hwm()) ? 0 : -1;
245 }
246
247 /***********************************************************
248  Delete a SID mapping from a winbindd_idmap.tdb
249  **********************************************************/
250 static int net_idmap_delete(int argc, const char **argv)
251 {
252         TDB_CONTEXT *idmap_tdb;
253         TDB_DATA key, data;
254         fstring sid;
255
256         if (argc != 2)
257                 return net_help_idmap(argc, argv);
258
259         idmap_tdb = tdb_open_log(argv[0], 0, TDB_DEFAULT, O_RDWR, 0);
260
261         if (idmap_tdb == NULL) {
262                 d_fprintf(stderr, "Could not open idmap: %s\n", argv[0]);
263                 return -1;
264         }
265
266         fstrcpy(sid, argv[1]);
267
268         if (strncmp(sid, "S-1-5-", strlen("S-1-5-")) != 0) {
269                 d_fprintf(stderr, "Can only delete SIDs, %s is does not start with "
270                          "S-1-5-\n", sid);
271                 return -1;
272         }
273
274         key.dptr = sid;
275         key.dsize = strlen(key.dptr)+1;
276
277         data = tdb_fetch(idmap_tdb, key);
278
279         if (data.dptr == NULL) {
280                 d_fprintf(stderr, "Could not find sid %s\n", argv[1]);
281                 return -1;
282         }
283
284         if (tdb_delete(idmap_tdb, key) != 0) {
285                 d_fprintf(stderr, "Could not delete key %s\n", argv[1]);
286                 return -1;
287         }
288
289         if (tdb_delete(idmap_tdb, data) != 0) {
290                 d_fprintf(stderr, "Could not delete key %s\n", data.dptr);
291                 return -1;
292         }
293
294         return 0;
295 }
296
297
298 int net_help_idmap(int argc, const char **argv)
299 {
300         d_printf("net idmap dump <tdbfile>"\
301                  "\n  Dump current id mapping\n");
302
303         d_printf("net idmap restore"\
304                  "\n  Restore entries from stdin to current local idmap\n");
305
306         /* Deliberately *not* document net idmap delete */
307
308         return -1;
309 }
310
311 /***********************************************************
312  Look at the current idmap
313  **********************************************************/
314 int net_idmap(int argc, const char **argv)
315 {
316         struct functable func[] = {
317                 {"dump", net_idmap_dump},
318                 {"restore", net_idmap_restore},
319                 {"delete", net_idmap_delete},
320                 {"help", net_help_idmap},
321                 {NULL, NULL}
322         };
323
324         return net_run_function(argc, argv, func, net_help_idmap);
325 }
326
327