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