Initial import
[samba] / source / 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 static int net_idmap_restore(int argc, const char **argv)
189 {
190         if (!idmap_init(lp_idmap_backend())) {
191                 d_fprintf(stderr, "Could not init idmap\n");
192                 return -1;
193         }
194
195         while (!feof(stdin)) {
196                 fstring line, sid_string;
197                 int len;
198                 unid_t id;
199                 int type = ID_EMPTY;
200                 DOM_SID sid;
201
202                 if (fgets(line, sizeof(line)-1, stdin) == NULL)
203                         break;
204
205                 len = strlen(line);
206
207                 if ( (len > 0) && (line[len-1] == '\n') )
208                         line[len-1] = '\0';
209
210                 /* Yuck - this is broken for sizeof(gid_t) != sizeof(int) */
211
212                 if (sscanf(line, "GID %d %s", &id.gid, sid_string) == 2) {
213                         type = ID_GROUPID;
214                 }
215
216                 /* Yuck - this is broken for sizeof(uid_t) != sizeof(int) */
217
218                 if (sscanf(line, "UID %d %s", &id.uid, sid_string) == 2) {
219                         type = ID_USERID;
220                 }
221
222                 if (type == ID_EMPTY) {
223                         d_printf("ignoring invalid line [%s]\n", line);
224                         continue;
225                 }
226
227                 if (!string_to_sid(&sid, sid_string)) {
228                         d_printf("ignoring invalid sid [%s]\n", sid_string);
229                         continue;
230                 }
231
232                 if (!NT_STATUS_IS_OK(idmap_set_mapping(&sid, id, type))) {
233                         d_fprintf(stderr, "Could not set mapping of %s %lu to sid %s\n",
234                                  (type == ID_GROUPID) ? "GID" : "UID",
235                                  (type == ID_GROUPID) ? (unsigned long)id.gid:
236                                  (unsigned long)id.uid, 
237                                  sid_string_static(&sid));
238                         continue;
239                 }
240                                  
241         }
242
243         idmap_close();
244
245         return NT_STATUS_IS_OK(net_idmap_fixup_hwm()) ? 0 : -1;
246 }
247
248 /***********************************************************
249  Delete a SID mapping from a winbindd_idmap.tdb
250  **********************************************************/
251 static int net_idmap_delete(int argc, const char **argv)
252 {
253         TDB_CONTEXT *idmap_tdb;
254         TDB_DATA key, data;
255         fstring sid;
256
257         if (argc != 2)
258                 return net_help_idmap(argc, argv);
259
260         idmap_tdb = tdb_open_log(argv[0], 0, TDB_DEFAULT, O_RDWR, 0);
261
262         if (idmap_tdb == NULL) {
263                 d_fprintf(stderr, "Could not open idmap: %s\n", argv[0]);
264                 return -1;
265         }
266
267         fstrcpy(sid, argv[1]);
268
269         if (strncmp(sid, "S-1-5-", strlen("S-1-5-")) != 0) {
270                 d_fprintf(stderr, "Can only delete SIDs, %s is does not start with "
271                          "S-1-5-\n", sid);
272                 return -1;
273         }
274
275         key.dptr = sid;
276         key.dsize = strlen(key.dptr)+1;
277
278         data = tdb_fetch(idmap_tdb, key);
279
280         if (data.dptr == NULL) {
281                 d_fprintf(stderr, "Could not find sid %s\n", argv[1]);
282                 return -1;
283         }
284
285         if (tdb_delete(idmap_tdb, key) != 0) {
286                 d_fprintf(stderr, "Could not delete key %s\n", argv[1]);
287                 return -1;
288         }
289
290         if (tdb_delete(idmap_tdb, data) != 0) {
291                 d_fprintf(stderr, "Could not delete key %s\n", data.dptr);
292                 return -1;
293         }
294
295         return 0;
296 }
297
298
299 int net_help_idmap(int argc, const char **argv)
300 {
301         d_printf("net idmap dump <tdbfile>"\
302                  "\n  Dump current id mapping\n");
303
304         d_printf("net idmap restore"\
305                  "\n  Restore entries from stdin to current local idmap\n");
306
307         /* Deliberately *not* document net idmap delete */
308
309         return -1;
310 }
311
312 /***********************************************************
313  Look at the current idmap
314  **********************************************************/
315 int net_idmap(int argc, const char **argv)
316 {
317         struct functable func[] = {
318                 {"dump", net_idmap_dump},
319                 {"restore", net_idmap_restore},
320                 {"delete", net_idmap_delete},
321                 {"help", net_help_idmap},
322                 {NULL, NULL}
323         };
324
325         return net_run_function(argc, argv, func, net_help_idmap);
326 }
327
328