Merge commit 'release-4-0-0alpha15' into master4-tmp
[amitay/samba.git] / source3 / lib / netapi / netapi.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  NetApi Support
4  *  Copyright (C) Guenther Deschner 2007-2008
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 3 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "lib/netapi/netapi.h"
22 #include "lib/netapi/netapi_private.h"
23 #include "secrets.h"
24 #include "krb5_env.h"
25
26 struct libnetapi_ctx *stat_ctx = NULL;
27 static bool libnetapi_initialized = false;
28
29 /****************************************************************
30 ****************************************************************/
31
32 static NET_API_STATUS libnetapi_init_private_context(struct libnetapi_ctx *ctx)
33 {
34         struct libnetapi_private_ctx *priv;
35
36         if (!ctx) {
37                 return W_ERROR_V(WERR_INVALID_PARAM);
38         }
39
40         priv = talloc_zero(ctx, struct libnetapi_private_ctx);
41         if (!priv) {
42                 return W_ERROR_V(WERR_NOMEM);
43         }
44
45         ctx->private_data = priv;
46
47         return NET_API_STATUS_SUCCESS;
48 }
49
50 /****************************************************************
51 Create a libnetapi context, for use in non-Samba applications.  This
52 loads the smb.conf file and sets the debug level to 0, so that
53 applications are not flooded with debug logs at level 10, when they
54 were not expecting it.
55 ****************************************************************/
56
57 NET_API_STATUS libnetapi_init(struct libnetapi_ctx **context)
58 {
59         NET_API_STATUS ret;
60         TALLOC_CTX *frame;
61         if (stat_ctx && libnetapi_initialized) {
62                 *context = stat_ctx;
63                 return NET_API_STATUS_SUCCESS;
64         }
65
66 #if 0
67         talloc_enable_leak_report();
68 #endif
69         frame = talloc_stackframe();
70
71         /* Case tables must be loaded before any string comparisons occour */
72         load_case_tables_library();
73
74         /* When libnetapi is invoked from an application, it does not
75          * want to be swamped with level 10 debug messages, even if
76          * this has been set for the server in smb.conf */
77         lp_set_cmdline("log level", "0");
78         setup_logging("libnetapi", DEBUG_STDERR);
79
80         if (!lp_load(get_dyn_CONFIGFILE(), true, false, false, true)) {
81                 TALLOC_FREE(frame);
82                 fprintf(stderr, "error loading %s\n", get_dyn_CONFIGFILE() );
83                 return W_ERROR_V(WERR_GENERAL_FAILURE);
84         }
85
86         init_names();
87         load_interfaces();
88         reopen_logs();
89
90         BlockSignals(True, SIGPIPE);
91
92         ret = libnetapi_net_init(context);
93         TALLOC_FREE(frame);
94         return ret;
95 }
96
97 /****************************************************************
98 Create a libnetapi context, for use inside the 'net' binary.
99
100 As we know net has already loaded the smb.conf file, and set the debug
101 level etc, this avoids doing so again (which causes trouble with -d on
102 the command line).
103 ****************************************************************/
104
105 NET_API_STATUS libnetapi_net_init(struct libnetapi_ctx **context)
106 {
107         NET_API_STATUS status;
108         struct libnetapi_ctx *ctx = NULL;
109         char *krb5_cc_env = NULL;
110
111         TALLOC_CTX *frame = talloc_stackframe();
112
113         ctx = talloc_zero(frame, struct libnetapi_ctx);
114         if (!ctx) {
115                 TALLOC_FREE(frame);
116                 return W_ERROR_V(WERR_NOMEM);
117         }
118
119         BlockSignals(True, SIGPIPE);
120
121         krb5_cc_env = getenv(KRB5_ENV_CCNAME);
122         if (!krb5_cc_env || (strlen(krb5_cc_env) == 0)) {
123                 ctx->krb5_cc_env = talloc_strdup(ctx, "MEMORY:libnetapi");
124                 setenv(KRB5_ENV_CCNAME, ctx->krb5_cc_env, 1);
125         }
126
127         if (getenv("USER")) {
128                 ctx->username = talloc_strdup(ctx, getenv("USER"));
129         } else {
130                 ctx->username = talloc_strdup(ctx, "");
131         }
132         if (!ctx->username) {
133                 TALLOC_FREE(frame);
134                 fprintf(stderr, "libnetapi_init: out of memory\n");
135                 return W_ERROR_V(WERR_NOMEM);
136         }
137
138         status = libnetapi_init_private_context(ctx);
139         if (status != 0) {
140                 TALLOC_FREE(frame);
141                 return status;
142         }
143
144         libnetapi_initialized = true;
145
146         talloc_steal(NULL, ctx);
147         *context = stat_ctx = ctx;
148         
149         TALLOC_FREE(frame);
150         return NET_API_STATUS_SUCCESS;
151 }
152
153 /****************************************************************
154  Return the static libnetapi context
155 ****************************************************************/
156
157 NET_API_STATUS libnetapi_getctx(struct libnetapi_ctx **ctx)
158 {
159         if (stat_ctx) {
160                 *ctx = stat_ctx;
161                 return NET_API_STATUS_SUCCESS;
162         }
163
164         return libnetapi_init(ctx);
165 }
166
167 /****************************************************************
168  Free the static libnetapi context
169 ****************************************************************/
170
171 NET_API_STATUS libnetapi_free(struct libnetapi_ctx *ctx)
172 {
173         if (!ctx) {
174                 return NET_API_STATUS_SUCCESS;
175         }
176
177         libnetapi_samr_free(ctx);
178
179         libnetapi_shutdown_cm(ctx);
180
181         if (ctx->krb5_cc_env) {
182                 char *env = getenv(KRB5_ENV_CCNAME);
183                 if (env && (strequal(ctx->krb5_cc_env, env))) {
184                         unsetenv(KRB5_ENV_CCNAME);
185                 }
186         }
187
188         gfree_names();
189         gfree_loadparm();
190         gfree_charcnv();
191         gfree_interfaces();
192
193         secrets_shutdown();
194
195         if (ctx == stat_ctx) {
196                 stat_ctx = NULL;
197         }
198         TALLOC_FREE(ctx);
199
200         gfree_debugsyms();
201
202         return NET_API_STATUS_SUCCESS;
203 }
204
205 /****************************************************************
206  Override the current log level for libnetapi
207 ****************************************************************/
208
209 NET_API_STATUS libnetapi_set_debuglevel(struct libnetapi_ctx *ctx,
210                                         const char *debuglevel)
211 {
212         TALLOC_CTX *frame = talloc_stackframe();
213         ctx->debuglevel = talloc_strdup(ctx, debuglevel);
214         
215         if (!lp_set_cmdline("log level", debuglevel)) {
216                 TALLOC_FREE(frame);
217                 return W_ERROR_V(WERR_GENERAL_FAILURE);
218         }
219         TALLOC_FREE(frame);
220         return NET_API_STATUS_SUCCESS;
221 }
222
223 /****************************************************************
224 ****************************************************************/
225
226 NET_API_STATUS libnetapi_get_debuglevel(struct libnetapi_ctx *ctx,
227                                         char **debuglevel)
228 {
229         *debuglevel = ctx->debuglevel;
230         return NET_API_STATUS_SUCCESS;
231 }
232
233 /****************************************************************
234 ****************************************************************/
235
236 NET_API_STATUS libnetapi_set_username(struct libnetapi_ctx *ctx,
237                                       const char *username)
238 {
239         TALLOC_FREE(ctx->username);
240         ctx->username = talloc_strdup(ctx, username ? username : "");
241
242         if (!ctx->username) {
243                 return W_ERROR_V(WERR_NOMEM);
244         }
245         return NET_API_STATUS_SUCCESS;
246 }
247
248 NET_API_STATUS libnetapi_set_password(struct libnetapi_ctx *ctx,
249                                       const char *password)
250 {
251         TALLOC_FREE(ctx->password);
252         ctx->password = talloc_strdup(ctx, password);
253         if (!ctx->password) {
254                 return W_ERROR_V(WERR_NOMEM);
255         }
256         return NET_API_STATUS_SUCCESS;
257 }
258
259 NET_API_STATUS libnetapi_set_workgroup(struct libnetapi_ctx *ctx,
260                                        const char *workgroup)
261 {
262         TALLOC_FREE(ctx->workgroup);
263         ctx->workgroup = talloc_strdup(ctx, workgroup);
264         if (!ctx->workgroup) {
265                 return W_ERROR_V(WERR_NOMEM);
266         }
267         return NET_API_STATUS_SUCCESS;
268 }
269
270 /****************************************************************
271 ****************************************************************/
272
273 NET_API_STATUS libnetapi_set_use_kerberos(struct libnetapi_ctx *ctx)
274 {
275         ctx->use_kerberos = true;
276         return NET_API_STATUS_SUCCESS;
277 }
278
279 NET_API_STATUS libnetapi_set_use_ccache(struct libnetapi_ctx *ctx)
280 {
281         ctx->use_ccache = true;
282         return NET_API_STATUS_SUCCESS;
283 }
284
285 /****************************************************************
286 Return a libnetapi error as a string, caller must free with NetApiBufferFree
287 ****************************************************************/
288
289 char *libnetapi_errstr(NET_API_STATUS status)
290 {
291         TALLOC_CTX *frame = talloc_stackframe();
292         char *ret;
293         if (status & 0xc0000000) {
294                 ret = talloc_strdup(NULL, 
295                                      get_friendly_nt_error_msg(NT_STATUS(status)));
296         } else {
297                 ret = talloc_strdup(NULL,
298                                     get_friendly_werror_msg(W_ERROR(status)));
299         }
300         TALLOC_FREE(frame);
301         return ret;
302 }
303
304 /****************************************************************
305 ****************************************************************/
306
307 NET_API_STATUS libnetapi_set_error_string(struct libnetapi_ctx *ctx,
308                                           const char *format, ...)
309 {
310         va_list args;
311
312         TALLOC_FREE(ctx->error_string);
313
314         va_start(args, format);
315         ctx->error_string = talloc_vasprintf(ctx, format, args);
316         va_end(args);
317
318         if (!ctx->error_string) {
319                 return W_ERROR_V(WERR_NOMEM);
320         }
321         return NET_API_STATUS_SUCCESS;
322 }
323
324 /****************************************************************
325 Return a libnetapi_errstr(), caller must free with NetApiBufferFree
326 ****************************************************************/
327
328 char *libnetapi_get_error_string(struct libnetapi_ctx *ctx,
329                                        NET_API_STATUS status_in)
330 {
331         NET_API_STATUS status;
332         struct libnetapi_ctx *tmp_ctx = ctx;
333
334         if (!tmp_ctx) {
335                 status = libnetapi_getctx(&tmp_ctx);
336                 if (status != 0) {
337                         return NULL;
338                 }
339         }
340
341         if (tmp_ctx->error_string) {
342                 return talloc_strdup(NULL, tmp_ctx->error_string);
343         }
344
345         return libnetapi_errstr(status_in);
346 }
347
348 /****************************************************************
349 ****************************************************************/
350
351 NET_API_STATUS NetApiBufferAllocate(uint32_t byte_count,
352                                     void **buffer)
353 {
354         void *buf = NULL;
355
356         if (!buffer) {
357                 return W_ERROR_V(WERR_INSUFFICIENT_BUFFER);
358         }
359
360         if (byte_count == 0) {
361                 goto done;
362         }
363
364         buf = talloc_size(NULL, byte_count);
365         if (!buf) {
366                 return W_ERROR_V(WERR_NOMEM);
367         }
368
369  done:
370         *buffer = buf;
371
372         return NET_API_STATUS_SUCCESS;
373 }
374
375 /****************************************************************
376 ****************************************************************/
377
378 NET_API_STATUS NetApiBufferFree(void *buffer)
379 {
380         if (!buffer) {
381                 return W_ERROR_V(WERR_INSUFFICIENT_BUFFER);
382         }
383
384         talloc_free(buffer);
385
386         return NET_API_STATUS_SUCCESS;
387 }