3f98b1250319d63dffd59ce23c0bea8ea6dc5c67
[nivanova/samba-autobuild/.git] / source3 / utils / smbcquotas.c
1 /* 
2    Unix SMB/CIFS implementation.
3    QUOTA get/set utility
4    
5    Copyright (C) Andrew Tridgell                2000
6    Copyright (C) Tim Potter                     2000
7    Copyright (C) Jeremy Allison                 2000
8    Copyright (C) Stefan (metze) Metzmacher      2003
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "../librpc/gen_ndr/ndr_lsa.h"
26 #include "rpc_client/cli_lsarpc.h"
27
28 static char *server;
29
30 /* numeric is set when the user wants numeric SIDs and ACEs rather
31    than going via LSA calls to resolve them */
32 static bool numeric;
33 static bool verbose;
34
35 enum todo_values {NOOP_QUOTA=0,FS_QUOTA,USER_QUOTA,LIST_QUOTA,SET_QUOTA};
36 enum exit_values {EXIT_OK, EXIT_FAILED, EXIT_PARSE_ERROR};
37
38 static struct cli_state *cli_ipc;
39 static struct rpc_pipe_client *global_pipe_hnd;
40 static struct policy_handle pol;
41 static bool got_policy_hnd;
42 static struct user_auth_info *smbcquotas_auth_info;
43
44 static struct cli_state *connect_one(const char *share);
45
46 /* Open cli connection and policy handle */
47
48 static bool cli_open_policy_hnd(void)
49 {
50         /* Initialise cli LSA connection */
51
52         if (!cli_ipc) {
53                 NTSTATUS ret;
54                 cli_ipc = connect_one("IPC$");
55                 ret = cli_rpc_pipe_open_noauth(cli_ipc,
56                                                &ndr_table_lsarpc.syntax_id,
57                                                &global_pipe_hnd);
58                 if (!NT_STATUS_IS_OK(ret)) {
59                                 return False;
60                 }
61         }
62
63         /* Open policy handle */
64
65         if (!got_policy_hnd) {
66
67                 /* Some systems don't support SEC_FLAG_MAXIMUM_ALLOWED,
68                    but NT sends 0x2000000 so we might as well do it too. */
69
70                 if (!NT_STATUS_IS_OK(rpccli_lsa_open_policy(global_pipe_hnd, talloc_tos(), True, 
71                                                          GENERIC_EXECUTE_ACCESS, &pol))) {
72                         return False;
73                 }
74
75                 got_policy_hnd = True;
76         }
77         
78         return True;
79 }
80
81 /* convert a SID to a string, either numeric or username/group */
82 static void SidToString(fstring str, struct dom_sid *sid, bool _numeric)
83 {
84         char **domains = NULL;
85         char **names = NULL;
86         enum lsa_SidType *types = NULL;
87
88         sid_to_fstring(str, sid);
89
90         if (_numeric) return;
91
92         /* Ask LSA to convert the sid to a name */
93
94         if (!cli_open_policy_hnd() ||
95             !NT_STATUS_IS_OK(rpccli_lsa_lookup_sids(global_pipe_hnd, talloc_tos(),
96                                                  &pol, 1, sid, &domains, 
97                                                  &names, &types)) ||
98             !domains || !domains[0] || !names || !names[0]) {
99                 return;
100         }
101
102         /* Converted OK */
103
104         slprintf(str, sizeof(fstring) - 1, "%s%s%s",
105                  domains[0], lp_winbind_separator(),
106                  names[0]);
107         
108 }
109
110 /* convert a string to a SID, either numeric or username/group */
111 static bool StringToSid(struct dom_sid *sid, const char *str)
112 {
113         enum lsa_SidType *types = NULL;
114         struct dom_sid *sids = NULL;
115         bool result = True;
116
117         if (strncmp(str, "S-", 2) == 0) {
118                 return string_to_sid(sid, str);
119         }
120
121         if (!cli_open_policy_hnd() ||
122             !NT_STATUS_IS_OK(rpccli_lsa_lookup_names(global_pipe_hnd, talloc_tos(),
123                                                   &pol, 1, &str, NULL, 1, &sids, 
124                                                   &types))) {
125                 result = False;
126                 goto done;
127         }
128
129         sid_copy(sid, &sids[0]);
130  done:
131
132         return result;
133 }
134
135 #define QUOTA_GET 1
136 #define QUOTA_SETLIM 2
137 #define QUOTA_SETFLAGS 3
138 #define QUOTA_LIST 4
139
140 enum {PARSE_FLAGS,PARSE_LIM};
141
142 static int parse_quota_set(TALLOC_CTX *ctx,
143                         char *set_str,
144                         char **pp_username_str,
145                         enum SMB_QUOTA_TYPE *qtype,
146                         int *cmd,
147                         SMB_NTQUOTA_STRUCT *pqt)
148 {
149         char *p = set_str,*p2;
150         int todo;
151         bool stop = False;
152         bool enable = False;
153         bool deny = False;
154
155         *pp_username_str = NULL;
156         if (strnequal(set_str,"UQLIM:",6)) {
157                 p += 6;
158                 *qtype = SMB_USER_QUOTA_TYPE;
159                 *cmd = QUOTA_SETLIM;
160                 todo = PARSE_LIM;
161                 if ((p2=strstr(p,":"))==NULL) {
162                         return -1;
163                 }
164
165                 *p2 = '\0';
166                 p2++;
167
168                 *pp_username_str = talloc_strdup(ctx, p);
169                 p = p2;
170         } else if (strnequal(set_str,"FSQLIM:",7)) {
171                 p +=7;
172                 *qtype = SMB_USER_FS_QUOTA_TYPE;
173                 *cmd = QUOTA_SETLIM;
174                 todo = PARSE_LIM;
175         } else if (strnequal(set_str,"FSQFLAGS:",9)) {
176                 p +=9;
177                 todo = PARSE_FLAGS;
178                 *qtype = SMB_USER_FS_QUOTA_TYPE;
179                 *cmd = QUOTA_SETFLAGS;
180         } else {
181                 return -1;
182         }
183
184         switch (todo) {
185                 case PARSE_LIM:
186                         if (sscanf(p,"%"PRIu64"/%"PRIu64,&pqt->softlim,&pqt->hardlim)!=2) {
187                                 return -1;
188                         }
189
190                         break;
191                 case PARSE_FLAGS:
192                         while (!stop) {
193
194                                 if ((p2=strstr(p,"/"))==NULL) {
195                                         stop = True;
196                                 } else {
197                                         *p2 = '\0';
198                                         p2++;
199                                 }
200
201                                 if (strnequal(p,"QUOTA_ENABLED",13)) {
202                                         enable = True;
203                                 } else if (strnequal(p,"DENY_DISK",9)) {
204                                         deny = True;
205                                 } else if (strnequal(p,"LOG_SOFTLIMIT",13)) {
206                                         pqt->qflags |= QUOTAS_LOG_THRESHOLD;
207                                 } else if (strnequal(p,"LOG_HARDLIMIT",13)) {
208                                         pqt->qflags |= QUOTAS_LOG_LIMIT;
209                                 } else {
210                                         return -1;
211                                 }
212
213                                 p=p2;
214                         }
215
216                         if (deny) {
217                                 pqt->qflags |= QUOTAS_DENY_DISK;
218                         } else if (enable) {
219                                 pqt->qflags |= QUOTAS_ENABLED;
220                         }
221
222                         break;
223         }
224
225         return 0;
226 }
227
228 static int do_quota(struct cli_state *cli,
229                 enum SMB_QUOTA_TYPE qtype,
230                 uint16 cmd,
231                 const char *username_str,
232                 SMB_NTQUOTA_STRUCT *pqt)
233 {
234         uint32 fs_attrs = 0;
235         uint16_t quota_fnum = 0;
236         SMB_NTQUOTA_LIST *qtl = NULL;
237         SMB_NTQUOTA_STRUCT qt;
238         ZERO_STRUCT(qt);
239
240         if (!NT_STATUS_IS_OK(cli_get_fs_attr_info(cli, &fs_attrs))) {
241                 d_printf("Failed to get the filesystem attributes %s.\n",
242                         cli_errstr(cli));
243                 return -1;
244         }
245
246         if (!(fs_attrs & FILE_VOLUME_QUOTAS)) {
247                 d_printf("Quotas are not supported by the server.\n");
248                 return 0;
249         }
250
251         if (!NT_STATUS_IS_OK(cli_get_quota_handle(cli, &quota_fnum))) {
252                 d_printf("Quotas are not enabled on this share.\n");
253                 d_printf("Failed to open %s  %s.\n",
254                         FAKE_FILE_NAME_QUOTA_WIN32,cli_errstr(cli));
255                 return -1;
256         }
257
258         switch(qtype) {
259                 case SMB_USER_QUOTA_TYPE:
260                         if (!StringToSid(&qt.sid, username_str)) {
261                                 d_printf("StringToSid() failed for [%s]\n",username_str);
262                                 return -1;
263                         }
264
265                         switch(cmd) {
266                                 case QUOTA_GET:
267                                         if (!cli_get_user_quota(cli, quota_fnum, &qt)) {
268                                                 d_printf("%s cli_get_user_quota %s\n",
269                                                          cli_errstr(cli),username_str);
270                                                 return -1;
271                                         }
272                                         dump_ntquota(&qt,verbose,numeric,SidToString);
273                                         break;
274                                 case QUOTA_SETLIM:
275                                         pqt->sid = qt.sid;
276                                         if (!cli_set_user_quota(cli, quota_fnum, pqt)) {
277                                                 d_printf("%s cli_set_user_quota %s\n",
278                                                          cli_errstr(cli),username_str);
279                                                 return -1;
280                                         }
281                                         if (!cli_get_user_quota(cli, quota_fnum, &qt)) {
282                                                 d_printf("%s cli_get_user_quota %s\n",
283                                                          cli_errstr(cli),username_str);
284                                                 return -1;
285                                         }
286                                         dump_ntquota(&qt,verbose,numeric,SidToString);
287                                         break;
288                                 case QUOTA_LIST:
289                                         if (!cli_list_user_quota(cli, quota_fnum, &qtl)) {
290                                                 d_printf("%s cli_set_user_quota %s\n",
291                                                          cli_errstr(cli),username_str);
292                                                 return -1;
293                                         }
294                                         dump_ntquota_list(&qtl,verbose,numeric,SidToString);
295                                         free_ntquota_list(&qtl);
296                                         break;
297                                 default:
298                                         d_printf("Unknown Error\n");
299                                         return -1;
300                         }
301                         break;
302                 case SMB_USER_FS_QUOTA_TYPE:
303                         switch(cmd) {
304                                 case QUOTA_GET:
305                                         if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) {
306                                                 d_printf("%s cli_get_fs_quota_info\n",
307                                                          cli_errstr(cli));
308                                                 return -1;
309                                         }
310                                         dump_ntquota(&qt,True,numeric,NULL);
311                                         break;
312                                 case QUOTA_SETLIM:
313                                         if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) {
314                                                 d_printf("%s cli_get_fs_quota_info\n",
315                                                          cli_errstr(cli));
316                                                 return -1;
317                                         }
318                                         qt.softlim = pqt->softlim;
319                                         qt.hardlim = pqt->hardlim;
320                                         if (!cli_set_fs_quota_info(cli, quota_fnum, &qt)) {
321                                                 d_printf("%s cli_set_fs_quota_info\n",
322                                                          cli_errstr(cli));
323                                                 return -1;
324                                         }
325                                         if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) {
326                                                 d_printf("%s cli_get_fs_quota_info\n",
327                                                          cli_errstr(cli));
328                                                 return -1;
329                                         }
330                                         dump_ntquota(&qt,True,numeric,NULL);
331                                         break;
332                                 case QUOTA_SETFLAGS:
333                                         if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) {
334                                                 d_printf("%s cli_get_fs_quota_info\n",
335                                                          cli_errstr(cli));
336                                                 return -1;
337                                         }
338                                         qt.qflags = pqt->qflags;
339                                         if (!cli_set_fs_quota_info(cli, quota_fnum, &qt)) {
340                                                 d_printf("%s cli_set_fs_quota_info\n",
341                                                          cli_errstr(cli));
342                                                 return -1;
343                                         }
344                                         if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) {
345                                                 d_printf("%s cli_get_fs_quota_info\n",
346                                                          cli_errstr(cli));
347                                                 return -1;
348                                         }
349                                         dump_ntquota(&qt,True,numeric,NULL);
350                                         break;
351                                 default:
352                                         d_printf("Unknown Error\n");
353                                         return -1;
354                         }
355                         break;
356                 default:
357                         d_printf("Unknown Error\n");
358                         return -1;
359         }
360
361         cli_close(cli, quota_fnum);
362
363         return 0;
364 }
365
366 /*****************************************************
367  Return a connection to a server.
368 *******************************************************/
369
370 static struct cli_state *connect_one(const char *share)
371 {
372         struct cli_state *c;
373         struct sockaddr_storage ss;
374         NTSTATUS nt_status;
375         uint32_t flags = 0;
376
377         zero_sockaddr(&ss);
378
379         if (get_cmdline_auth_info_use_machine_account(smbcquotas_auth_info) &&
380             !set_cmdline_auth_info_machine_account_creds(smbcquotas_auth_info)) {
381                 return NULL;
382         }
383
384         if (get_cmdline_auth_info_use_kerberos(smbcquotas_auth_info)) {
385                 flags |= CLI_FULL_CONNECTION_USE_KERBEROS |
386                          CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
387
388         }
389
390         set_cmdline_auth_info_getpass(smbcquotas_auth_info);
391
392         nt_status = cli_full_connection(&c, global_myname(), server, 
393                                             &ss, 0,
394                                             share, "?????",
395                                             get_cmdline_auth_info_username(smbcquotas_auth_info),
396                                             lp_workgroup(),
397                                             get_cmdline_auth_info_password(smbcquotas_auth_info),
398                                             flags,
399                                             get_cmdline_auth_info_signing_state(smbcquotas_auth_info),
400                                             NULL);
401         if (!NT_STATUS_IS_OK(nt_status)) {
402                 DEBUG(0,("cli_full_connection failed! (%s)\n", nt_errstr(nt_status)));
403                 return NULL;
404         }
405
406         if (get_cmdline_auth_info_smb_encrypt(smbcquotas_auth_info)) {
407                 nt_status = cli_cm_force_encryption(c,
408                                         get_cmdline_auth_info_username(smbcquotas_auth_info),
409                                         get_cmdline_auth_info_password(smbcquotas_auth_info),
410                                         lp_workgroup(),
411                                         share);
412                 if (!NT_STATUS_IS_OK(nt_status)) {
413                         cli_shutdown(c);
414                         return NULL;
415                 }
416         }
417
418         return c;
419 }
420
421 /****************************************************************************
422   main program
423 ****************************************************************************/
424  int main(int argc, const char *argv[])
425 {
426         char *share;
427         int opt;
428         int result;
429         int todo = 0;
430         char *username_str = NULL;
431         char *path = NULL;
432         char *set_str = NULL;
433         enum SMB_QUOTA_TYPE qtype = SMB_INVALID_QUOTA_TYPE;
434         int cmd = 0;
435         static bool test_args = False;
436         struct cli_state *cli;
437         bool fix_user = False;
438         SMB_NTQUOTA_STRUCT qt;
439         TALLOC_CTX *frame = talloc_stackframe();
440         poptContext pc;
441         struct poptOption long_options[] = {
442                 POPT_AUTOHELP
443                 { "user", 'u', POPT_ARG_STRING, NULL, 'u', "Show quotas for user", "user" },
444                 { "list", 'L', POPT_ARG_NONE, NULL, 'L', "List user quotas" },
445                 { "fs", 'F', POPT_ARG_NONE, NULL, 'F', "Show filesystem quotas" },
446                 { "set", 'S', POPT_ARG_STRING, NULL, 'S', "Set acls\n\
447 SETSTRING:\n\
448 UQLIM:<username>/<softlimit>/<hardlimit> for user quotas\n\
449 FSQLIM:<softlimit>/<hardlimit> for filesystem defaults\n\
450 FSQFLAGS:QUOTA_ENABLED/DENY_DISK/LOG_SOFTLIMIT/LOG_HARD_LIMIT", "SETSTRING" },
451                 { "numeric", 'n', POPT_ARG_NONE, NULL, 'n', "Don't resolve sids or limits to names" },
452                 { "verbose", 'v', POPT_ARG_NONE, NULL, 'v', "be verbose" },
453                 { "test-args", 't', POPT_ARG_NONE, NULL, 'r', "Test arguments"},
454                 POPT_COMMON_SAMBA
455                 POPT_COMMON_CREDENTIALS
456                 { NULL }
457         };
458
459         load_case_tables();
460
461         ZERO_STRUCT(qt);
462
463         /* set default debug level to 1 regardless of what smb.conf sets */
464         setup_logging( "smbcquotas", True );
465         DEBUGLEVEL_CLASS[DBGC_ALL] = 1;
466         dbf = x_stderr;
467         x_setbuf( x_stderr, NULL );
468
469         setlinebuf(stdout);
470
471         fault_setup(NULL);
472
473         lp_load(get_dyn_CONFIGFILE(),True,False,False,True);
474         load_interfaces();
475
476         smbcquotas_auth_info = user_auth_info_init(frame);
477         if (smbcquotas_auth_info == NULL) {
478                 exit(1);
479         }
480         popt_common_set_auth_info(smbcquotas_auth_info);
481
482         pc = poptGetContext("smbcquotas", argc, argv, long_options, 0);
483
484         poptSetOtherOptionHelp(pc, "//server1/share1");
485
486         while ((opt = poptGetNextOpt(pc)) != -1) {
487                 switch (opt) {
488                 case 'n':
489                         numeric = true;
490                         break;
491                 case 'v':
492                         verbose = true;
493                         break;
494                 case 't':
495                         test_args = true;
496                         break;
497                 case 'L':
498                         if (todo != 0) {
499                                 d_printf("Please specify only one option of <-L|-F|-S|-u>\n");
500                                 exit(EXIT_PARSE_ERROR);
501                         }
502                         todo = LIST_QUOTA;
503                         break;
504
505                 case 'F':
506                         if (todo != 0) {
507                                 d_printf("Please specify only one option of <-L|-F|-S|-u>\n");
508                                 exit(EXIT_PARSE_ERROR);
509                         }
510                         todo = FS_QUOTA;
511                         break;
512
513                 case 'u':
514                         if (todo != 0) {
515                                 d_printf("Please specify only one option of <-L|-F|-S|-u>\n");
516                                 exit(EXIT_PARSE_ERROR);
517                         }
518                         username_str = talloc_strdup(frame, poptGetOptArg(pc));
519                         if (!username_str) {
520                                 exit(EXIT_PARSE_ERROR);
521                         }
522                         todo = USER_QUOTA;
523                         fix_user = True;
524                         break;
525
526                 case 'S':
527                         if (todo != 0) {
528                                 d_printf("Please specify only one option of <-L|-F|-S|-u>\n");
529                                 exit(EXIT_PARSE_ERROR);
530                         }
531                         set_str = talloc_strdup(frame, poptGetOptArg(pc));
532                         if (!set_str) {
533                                 exit(EXIT_PARSE_ERROR);
534                         }
535                         todo = SET_QUOTA;
536                         break;
537                 }
538         }
539
540         if (todo == 0)
541                 todo = USER_QUOTA;
542
543         if (!fix_user) {
544                 username_str = talloc_strdup(
545                         frame, get_cmdline_auth_info_username(smbcquotas_auth_info));
546                 if (!username_str) {
547                         exit(EXIT_PARSE_ERROR);
548                 }
549         }
550
551         /* Make connection to server */
552         if(!poptPeekArg(pc)) {
553                 poptPrintUsage(pc, stderr, 0);
554                 exit(EXIT_PARSE_ERROR);
555         }
556
557         path = talloc_strdup(frame, poptGetArg(pc));
558         if (!path) {
559                 printf("Out of memory\n");
560                 exit(EXIT_PARSE_ERROR);
561         }
562
563         string_replace(path, '/', '\\');
564
565         server = SMB_STRDUP(path+2);
566         if (!server) {
567                 printf("Out of memory\n");
568                 exit(EXIT_PARSE_ERROR);
569         }
570         share = strchr_m(server,'\\');
571         if (!share) {
572                 printf("Invalid argument: %s\n", share);
573                 exit(EXIT_PARSE_ERROR);
574         }
575
576         *share = 0;
577         share++;
578
579         if (todo == SET_QUOTA) {
580                 if (parse_quota_set(talloc_tos(), set_str, &username_str, &qtype, &cmd, &qt)) {
581                         printf("Invalid argument: -S %s\n", set_str);
582                         exit(EXIT_PARSE_ERROR);
583                 }
584         }
585
586         if (!test_args) {
587                 cli = connect_one(share);
588                 if (!cli) {
589                         exit(EXIT_FAILED);
590                 }
591         } else {
592                 exit(EXIT_OK);
593         }
594
595
596         /* Perform requested action */
597
598         switch (todo) {
599                 case FS_QUOTA:
600                         result = do_quota(cli,SMB_USER_FS_QUOTA_TYPE, QUOTA_GET, username_str, NULL);
601                         break;
602                 case LIST_QUOTA:
603                         result = do_quota(cli,SMB_USER_QUOTA_TYPE, QUOTA_LIST, username_str, NULL);
604                         break;
605                 case USER_QUOTA:
606                         result = do_quota(cli,SMB_USER_QUOTA_TYPE, QUOTA_GET, username_str, NULL);
607                         break;
608                 case SET_QUOTA:
609                         result = do_quota(cli, qtype, cmd, username_str, &qt);
610                         break;
611                 default: 
612                         
613                         result = EXIT_FAILED;
614                         break;
615         }
616
617         talloc_free(frame);
618
619         return result;
620 }