Working on bug #5475
[kai/samba.git] / examples / libsmbclient / testacl.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <errno.h>
4 #include <popt.h>
5 #include "libsmbclient.h"
6 #include "get_auth_data_fn.h"
7
8 enum acl_mode
9 {
10     SMB_ACL_LIST,
11     SMB_ACL_GET,
12     SMB_ACL_SET,
13     SMB_ACL_DELETE,
14     SMB_ACL_MODIFY,
15     SMB_ACL_ADD,
16     SMB_ACL_CHOWN,
17     SMB_ACL_CHGRP
18 };
19
20
21 int main(int argc, const char *argv[])
22 {
23     int opt;
24     int flags;
25     int debug = 0;
26     int numeric = 0;
27     int stat_and_retry = 0;
28     int full_time_names = 0;
29     enum acl_mode mode = SMB_ACL_LIST;
30     static char *the_acl = NULL;
31     int ret;
32     char *p;
33     char *debugstr;
34     char path[1024];
35     char value[1024];
36     poptContext pc;
37     struct stat st;
38     struct poptOption long_options[] =
39         {
40             POPT_AUTOHELP
41             {
42                 "numeric", 'n', POPT_ARG_NONE, &numeric,
43                 1, "Don't resolve sids or masks to names"
44             },
45             {
46                 "debug", 'd', POPT_ARG_INT, &debug,
47                 0, "Set debug level (0-100)"
48             },
49             {
50                 "full_time_names", 'f', POPT_ARG_NONE, &full_time_names,
51                 1,
52                 "Use new style xattr names, which include CREATE_TIME"
53             },
54             {
55                 "delete", 'D', POPT_ARG_STRING, NULL,
56                 'D', "Delete an acl", "ACL"
57             },
58             {
59                 "modify", 'M', POPT_ARG_STRING, NULL,
60                 'M', "Modify an acl", "ACL"
61             },
62             {
63                 "add", 'a', POPT_ARG_STRING, NULL,
64                 'a', "Add an acl", "ACL"
65             },
66             {
67                 "set", 'S', POPT_ARG_STRING, NULL,
68                 'S', "Set acls", "ACLS"
69             },
70             {
71                 "chown", 'C', POPT_ARG_STRING, NULL,
72                 'C', "Change ownership of a file", "USERNAME"
73             },
74             {
75                 "chgrp", 'G', POPT_ARG_STRING, NULL,
76                 'G', "Change group ownership of a file", "GROUPNAME"
77             },
78             {
79                 "get", 'g', POPT_ARG_STRING, NULL,
80                 'g', "Get a specific acl attribute", "ACL"
81             },
82             {
83                 "stat_and_retry", 'R', POPT_ARG_NONE, &stat_and_retry,
84                 1, "After 'get' do 'stat' and another 'get'"
85             },
86             {
87                 NULL
88             }
89         };
90     
91     setbuf(stdout, NULL);
92
93     pc = poptGetContext("smbcacls", argc, argv, long_options, 0);
94     
95     poptSetOtherOptionHelp(pc, "smb://server1/share1/filename");
96     
97     while ((opt = poptGetNextOpt(pc)) != -1) {
98         switch (opt) {
99         case 'S':
100             the_acl = strdup(poptGetOptArg(pc));
101             mode = SMB_ACL_SET;
102             break;
103             
104         case 'D':
105             the_acl = strdup(poptGetOptArg(pc));
106             mode = SMB_ACL_DELETE;
107             break;
108             
109         case 'M':
110             the_acl = strdup(poptGetOptArg(pc));
111             mode = SMB_ACL_MODIFY;
112             break;
113             
114         case 'a':
115             the_acl = strdup(poptGetOptArg(pc));
116             mode = SMB_ACL_ADD;
117             break;
118
119         case 'g':
120             the_acl = strdup(poptGetOptArg(pc));
121             mode = SMB_ACL_GET;
122             break;
123
124         case 'C':
125             the_acl = strdup(poptGetOptArg(pc));
126             mode = SMB_ACL_CHOWN;
127             break;
128
129         case 'G':
130             the_acl = strdup(poptGetOptArg(pc));
131             mode = SMB_ACL_CHGRP;
132             break;
133         }
134     }
135     
136     /* Make connection to server */
137     if(!poptPeekArg(pc)) { 
138         poptPrintUsage(pc, stderr, 0);
139         return 1;
140     }
141     
142     strcpy(path, poptGetArg(pc));
143     
144     if (smbc_init(get_auth_data_fn, debug) != 0)
145     {
146         printf("Could not initialize smbc_ library\n");
147         return 1;
148     }
149
150     if (full_time_names) {
151         SMBCCTX *context = smbc_set_context(NULL);
152         smbc_setOptionFullTimeNames(context, 1);
153     }
154     
155     /* Perform requested action */
156     
157     switch(mode)
158     {
159     case SMB_ACL_LIST:
160         ret = smbc_listxattr(path, value, sizeof(value)-2);
161         if (ret < 0)
162         {
163             printf("Could not get attribute list for [%s] %d: %s\n",
164                    path, errno, strerror(errno));
165             return 1;
166         }
167
168         /*
169          * The list of attributes has a series of null-terminated strings.
170          * The list of strings terminates with an extra null byte, thus two in
171          * a row.  Ensure that our buffer, which is conceivably shorter than
172          * the list of attributes, actually ends with two null bytes in a row.
173          */
174         value[sizeof(value) - 2] = '\0';
175         value[sizeof(value) - 1] = '\0';
176         printf("Supported attributes:\n");
177         for (p = value; *p; p += strlen(p) + 1)
178         {
179             printf("\t%s\n", p);
180         }
181         break;
182
183     case SMB_ACL_GET:
184         do
185         {
186             if (the_acl == NULL)
187             {
188                 if (numeric)
189                 {
190                     the_acl = "system.*";
191                 }
192                 else
193                 {
194                     the_acl = "system.*+";
195                 }
196             }
197             ret = smbc_getxattr(path, the_acl, value, sizeof(value));
198             if (ret < 0)
199             {
200                 printf("Could not get attributes for [%s] %d: %s\n",
201                        path, errno, strerror(errno));
202                 return 1;
203             }
204         
205             printf("Attributes for [%s] are:\n%s\n", path, value);
206
207             if (stat_and_retry)
208             {
209                 if (smbc_stat(path, &st) < 0)
210                 {
211                     perror("smbc_stat");
212                     return 1;
213                 }
214             }
215
216             --stat_and_retry;
217         } while (stat_and_retry >= 0);
218         break;
219
220     case SMB_ACL_ADD:
221         flags = SMBC_XATTR_FLAG_CREATE;
222         debugstr = "add attributes";
223         goto do_set;
224         
225     case SMB_ACL_MODIFY:
226         flags = SMBC_XATTR_FLAG_REPLACE;
227         debugstr = "modify attributes";
228         goto do_set;
229
230     case SMB_ACL_CHOWN:
231         snprintf(value, sizeof(value),
232                  "system.nt_sec_desc.owner%s:%s",
233                  numeric ? "" : "+", the_acl);
234         the_acl = value;
235         debugstr = "chown owner";
236         goto do_set;
237
238     case SMB_ACL_CHGRP:
239         snprintf(value, sizeof(value),
240                  "system.nt_sec_desc.group%s:%s",
241                  numeric ? "" : "+", the_acl);
242         the_acl = value;
243         debugstr = "change group";
244         goto do_set;
245
246     case SMB_ACL_SET:
247         flags = 0;
248         debugstr = "set attributes";
249         
250       do_set:
251         if ((p = strchr(the_acl, ':')) == NULL)
252         {
253             printf("Missing value.  ACL must be name:value pair\n");
254             return 1;
255         }
256
257         *p++ = '\0';
258         
259         ret = smbc_setxattr(path, the_acl, p, strlen(p), flags);
260         if (ret < 0)
261         {
262             printf("Could not %s for [%s] %d: %s\n",
263                    debugstr, path, errno, strerror(errno));
264             return 1;
265         }
266         break;
267
268     case SMB_ACL_DELETE:
269         ret = smbc_removexattr(path, the_acl);
270         if (ret < 0)
271         {
272             printf("Could not remove attribute %s for [%s] %d:%s\n",
273                    the_acl, path, errno, strerror(errno));
274             return 1;
275         }
276         break;
277
278     default:
279         printf("operation not yet implemented\n");
280         break;
281     }
282     
283     return 0;
284 }