~vcs-imports/samba/main

« back to all changes in this revision

Viewing changes to source/libsmb/libsmbclient.c

  • Committer: jerry
  • Date: 2006-07-14 21:48:39 UTC
  • Revision ID: vcs-imports@canonical.com-20060714214839-586d8c489a8fcead
gutting trunk to move to svn:externals

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* 
2
 
   Unix SMB/Netbios implementation.
3
 
   SMB client library implementation
4
 
   Copyright (C) Andrew Tridgell 1998
5
 
   Copyright (C) Richard Sharpe 2000, 2002
6
 
   Copyright (C) John Terpstra 2000
7
 
   Copyright (C) Tom Jansen (Ninja ISD) 2002 
8
 
   Copyright (C) Derrell Lipman 2003, 2004
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 2 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, write to the Free Software
22
 
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
 
*/
24
 
 
25
 
#include "includes.h"
26
 
 
27
 
#include "include/libsmb_internal.h"
28
 
 
29
 
 
30
 
/*
31
 
 * DOS Attribute values (used internally)
32
 
 */
33
 
typedef struct DOS_ATTR_DESC {
34
 
        int mode;
35
 
        SMB_OFF_T size;
36
 
        time_t a_time;
37
 
        time_t c_time;
38
 
        time_t m_time;
39
 
        SMB_INO_T inode;
40
 
} DOS_ATTR_DESC;
41
 
 
42
 
 
43
 
/*
44
 
 * Internal flags for extended attributes
45
 
 */
46
 
 
47
 
/* internal mode values */
48
 
#define SMBC_XATTR_MODE_ADD          1
49
 
#define SMBC_XATTR_MODE_REMOVE       2
50
 
#define SMBC_XATTR_MODE_REMOVE_ALL   3
51
 
#define SMBC_XATTR_MODE_SET          4
52
 
#define SMBC_XATTR_MODE_CHOWN        5
53
 
#define SMBC_XATTR_MODE_CHGRP        6
54
 
 
55
 
#define CREATE_ACCESS_READ      READ_CONTROL_ACCESS
56
 
 
57
 
/*We should test for this in configure ... */
58
 
#ifndef ENOTSUP
59
 
#define ENOTSUP EOPNOTSUPP
60
 
#endif
61
 
 
62
 
/*
63
 
 * Functions exported by libsmb_cache.c that we need here
64
 
 */
65
 
int smbc_default_cache_functions(SMBCCTX *context);
66
 
 
67
 
/* 
68
 
 * check if an element is part of the list. 
69
 
 * FIXME: Does not belong here !  
70
 
 * Can anyone put this in a macro in dlinklist.h ?
71
 
 * -- Tom
72
 
 */
73
 
static int DLIST_CONTAINS(SMBCFILE * list, SMBCFILE *p) {
74
 
        if (!p || !list) return False;
75
 
        do {
76
 
                if (p == list) return True;
77
 
                list = list->next;
78
 
        } while (list);
79
 
        return False;
80
 
}
81
 
 
82
 
/*
83
 
 * Find an lsa pipe handle associated with a cli struct.
84
 
 */
85
 
static struct rpc_pipe_client *
86
 
find_lsa_pipe_hnd(struct cli_state *ipc_cli)
87
 
{
88
 
        struct rpc_pipe_client *pipe_hnd;
89
 
 
90
 
        for (pipe_hnd = ipc_cli->pipe_list;
91
 
             pipe_hnd;
92
 
             pipe_hnd = pipe_hnd->next) {
93
 
            
94
 
                if (pipe_hnd->pipe_idx == PI_LSARPC) {
95
 
                        return pipe_hnd;
96
 
                }
97
 
        }
98
 
 
99
 
        return NULL;
100
 
}
101
 
 
102
 
static int
103
 
smbc_close_ctx(SMBCCTX *context,
104
 
               SMBCFILE *file);
105
 
static off_t
106
 
smbc_lseek_ctx(SMBCCTX *context,
107
 
               SMBCFILE *file,
108
 
               off_t offset,
109
 
               int whence);
110
 
 
111
 
extern BOOL in_client;
112
 
 
113
 
/*
114
 
 * Is the logging working / configfile read ? 
115
 
 */
116
 
static int smbc_initialized = 0;
117
 
 
118
 
static int 
119
 
hex2int( unsigned int _char )
120
 
{
121
 
    if ( _char >= 'A' && _char <='F')
122
 
        return _char - 'A' + 10;
123
 
    if ( _char >= 'a' && _char <='f')
124
 
        return _char - 'a' + 10;
125
 
    if ( _char >= '0' && _char <='9')
126
 
        return _char - '0';
127
 
    return -1;
128
 
}
129
 
 
130
 
/*
131
 
 * smbc_urldecode()
132
 
 *
133
 
 * Convert strings of %xx to their single character equivalent.  Each 'x' must
134
 
 * be a valid hexadecimal digit, or that % sequence is left undecoded.
135
 
 *
136
 
 * dest may, but need not be, the same pointer as src.
137
 
 *
138
 
 * Returns the number of % sequences which could not be converted due to lack
139
 
 * of two following hexadecimal digits.
140
 
 */
141
 
int
142
 
smbc_urldecode(char *dest, char * src, size_t max_dest_len)
143
 
{
144
 
        int old_length = strlen(src);
145
 
        int i = 0;
146
 
        int err_count = 0;
147
 
        pstring temp;
148
 
        char * p;
149
 
 
150
 
        if ( old_length == 0 ) {
151
 
                return 0;
152
 
        }
153
 
 
154
 
        p = temp;
155
 
        while ( i < old_length ) {
156
 
                unsigned char character = src[ i++ ];
157
 
 
158
 
                if (character == '%') {
159
 
                        int a = i+1 < old_length ? hex2int( src[i] ) : -1;
160
 
                        int b = i+1 < old_length ? hex2int( src[i+1] ) : -1;
161
 
 
162
 
                        /* Replace valid sequence */
163
 
                        if (a != -1 && b != -1) {
164
 
 
165
 
                                /* Replace valid %xx sequence with %dd */
166
 
                                character = (a * 16) + b;
167
 
 
168
 
                                if (character == '\0') {
169
 
                                        break; /* Stop at %00 */
170
 
                                }
171
 
 
172
 
                                i += 2;
173
 
                        } else {
174
 
 
175
 
                                err_count++;
176
 
                        }
177
 
                }
178
 
 
179
 
                *p++ = character;
180
 
        }
181
 
 
182
 
        *p = '\0';
183
 
 
184
 
        strncpy(dest, temp, max_dest_len - 1);
185
 
        dest[max_dest_len - 1] = '\0';
186
 
 
187
 
        return err_count;
188
 
}
189
 
 
190
 
/*
191
 
 * smbc_urlencode()
192
 
 *
193
 
 * Convert any characters not specifically allowed in a URL into their %xx
194
 
 * equivalent.
195
 
 *
196
 
 * Returns the remaining buffer length.
197
 
 */
198
 
int
199
 
smbc_urlencode(char * dest, char * src, int max_dest_len)
200
 
{
201
 
        char hex[] = "0123456789ABCDEF";
202
 
 
203
 
        for (; *src != '\0' && max_dest_len >= 3; src++) {
204
 
 
205
 
                if ((*src < '0' &&
206
 
                     *src != '-' &&
207
 
                     *src != '.') ||
208
 
                    (*src > '9' &&
209
 
                     *src < 'A') ||
210
 
                    (*src > 'Z' &&
211
 
                     *src < 'a' &&
212
 
                     *src != '_') ||
213
 
                    (*src > 'z')) {
214
 
                        *dest++ = '%';
215
 
                        *dest++ = hex[(*src >> 4) & 0x0f];
216
 
                        *dest++ = hex[*src & 0x0f];
217
 
                        max_dest_len -= 3;
218
 
                } else {
219
 
                        *dest++ = *src;
220
 
                        max_dest_len--;
221
 
                }
222
 
        }
223
 
 
224
 
        *dest++ = '\0';
225
 
        max_dest_len--;
226
 
        
227
 
        return max_dest_len;
228
 
}
229
 
 
230
 
/*
231
 
 * Function to parse a path and turn it into components
232
 
 *
233
 
 * The general format of an SMB URI is explain in Christopher Hertel's CIFS
234
 
 * book, at http://ubiqx.org/cifs/Appendix-D.html.  We accept a subset of the
235
 
 * general format ("smb:" only; we do not look for "cifs:").
236
 
 *
237
 
 *
238
 
 * We accept:
239
 
 *  smb://[[[domain;]user[:password]@]server[/share[/path[/file]]]][?options]
240
 
 *
241
 
 * Meaning of URLs:
242
 
 *
243
 
 * smb://           Show all workgroups.
244
 
 *
245
 
 *                  The method of locating the list of workgroups varies
246
 
 *                  depending upon the setting of the context variable
247
 
 *                  context->options.browse_max_lmb_count.  This value
248
 
 *                  determine the maximum number of local master browsers to
249
 
 *                  query for the list of workgroups.  In order to ensure that
250
 
 *                  a complete list of workgroups is obtained, all master
251
 
 *                  browsers must be queried, but if there are many
252
 
 *                  workgroups, the time spent querying can begin to add up.
253
 
 *                  For small networks (not many workgroups), it is suggested
254
 
 *                  that this variable be set to 0, indicating query all local
255
 
 *                  master browsers.  When the network has many workgroups, a
256
 
 *                  reasonable setting for this variable might be around 3.
257
 
 *
258
 
 * smb://name/      if name<1D> or name<1B> exists, list servers in
259
 
 *                  workgroup, else, if name<20> exists, list all shares
260
 
 *                  for server ...
261
 
 *
262
 
 * If "options" are provided, this function returns the entire option list as a
263
 
 * string, for later parsing by the caller.  Note that currently, no options
264
 
 * are supported.
265
 
 */
266
 
 
267
 
static const char *smbc_prefix = "smb:";
268
 
 
269
 
static int
270
 
smbc_parse_path(SMBCCTX *context,
271
 
                const char *fname,
272
 
                char *workgroup, int workgroup_len,
273
 
                char *server, int server_len,
274
 
                char *share, int share_len,
275
 
                char *path, int path_len,
276
 
                char *user, int user_len,
277
 
                char *password, int password_len,
278
 
                char *options, int options_len)
279
 
{
280
 
        static pstring s;
281
 
        pstring userinfo;
282
 
        const char *p;
283
 
        char *q, *r;
284
 
        int len;
285
 
 
286
 
        server[0] = share[0] = path[0] = user[0] = password[0] = (char)0;
287
 
 
288
 
        /*
289
 
         * Assume we wont find an authentication domain to parse, so default
290
 
         * to the workgroup in the provided context.
291
 
         */
292
 
        if (workgroup != NULL) {
293
 
                strncpy(workgroup, context->workgroup, workgroup_len - 1);
294
 
                workgroup[workgroup_len - 1] = '\0';
295
 
        }
296
 
 
297
 
        if (options != NULL && options_len > 0) {
298
 
                options[0] = (char)0;
299
 
        }
300
 
        pstrcpy(s, fname);
301
 
 
302
 
        /* see if it has the right prefix */
303
 
        len = strlen(smbc_prefix);
304
 
        if (strncmp(s,smbc_prefix,len) || (s[len] != '/' && s[len] != 0)) {
305
 
                return -1; /* What about no smb: ? */
306
 
        }
307
 
 
308
 
        p = s + len;
309
 
 
310
 
        /* Watch the test below, we are testing to see if we should exit */
311
 
 
312
 
        if (strncmp(p, "//", 2) && strncmp(p, "\\\\", 2)) {
313
 
 
314
 
                DEBUG(1, ("Invalid path (does not begin with smb://"));
315
 
                return -1;
316
 
 
317
 
        }
318
 
 
319
 
        p += 2;  /* Skip the double slash */
320
 
 
321
 
        /* See if any options were specified */
322
 
        if ((q = strrchr(p, '?')) != NULL ) {
323
 
                /* There are options.  Null terminate here and point to them */
324
 
                *q++ = '\0';
325
 
                
326
 
                DEBUG(4, ("Found options '%s'", q));
327
 
 
328
 
                /* Copy the options */
329
 
                if (options != NULL && options_len > 0) {
330
 
                        safe_strcpy(options, q, options_len - 1);
331
 
                }
332
 
        }
333
 
 
334
 
        if (*p == (char)0)
335
 
            goto decoding;
336
 
 
337
 
        if (*p == '/') {
338
 
 
339
 
                strncpy(server, context->workgroup, 
340
 
                        ((strlen(context->workgroup) < 16)
341
 
                         ? strlen(context->workgroup)
342
 
                         : 16));
343
 
                server[server_len - 1] = '\0';
344
 
                return 0;
345
 
                
346
 
        }
347
 
 
348
 
        /*
349
 
         * ok, its for us. Now parse out the server, share etc. 
350
 
         *
351
 
         * However, we want to parse out [[domain;]user[:password]@] if it
352
 
         * exists ...
353
 
         */
354
 
 
355
 
        /* check that '@' occurs before '/', if '/' exists at all */
356
 
        q = strchr_m(p, '@');
357
 
        r = strchr_m(p, '/');
358
 
        if (q && (!r || q < r)) {
359
 
                pstring username, passwd, domain;
360
 
                const char *u = userinfo;
361
 
 
362
 
                next_token_no_ltrim(&p, userinfo, "@", sizeof(fstring));
363
 
 
364
 
                username[0] = passwd[0] = domain[0] = 0;
365
 
 
366
 
                if (strchr_m(u, ';')) {
367
 
      
368
 
                        next_token_no_ltrim(&u, domain, ";", sizeof(fstring));
369
 
 
370
 
                }
371
 
 
372
 
                if (strchr_m(u, ':')) {
373
 
 
374
 
                        next_token_no_ltrim(&u, username, ":", sizeof(fstring));
375
 
 
376
 
                        pstrcpy(passwd, u);
377
 
 
378
 
                }
379
 
                else {
380
 
 
381
 
                        pstrcpy(username, u);
382
 
 
383
 
                }
384
 
 
385
 
                if (domain[0] && workgroup) {
386
 
                        strncpy(workgroup, domain, workgroup_len - 1);
387
 
                        workgroup[workgroup_len - 1] = '\0';
388
 
                }
389
 
 
390
 
                if (username[0]) {
391
 
                        strncpy(user, username, user_len - 1);
392
 
                        user[user_len - 1] = '\0';
393
 
                }
394
 
 
395
 
                if (passwd[0]) {
396
 
                        strncpy(password, passwd, password_len - 1);
397
 
                        password[password_len - 1] = '\0';
398
 
                }
399
 
 
400
 
        }
401
 
 
402
 
        if (!next_token(&p, server, "/", sizeof(fstring))) {
403
 
 
404
 
                return -1;
405
 
 
406
 
        }
407
 
 
408
 
        if (*p == (char)0) goto decoding;  /* That's it ... */
409
 
  
410
 
        if (!next_token(&p, share, "/", sizeof(fstring))) {
411
 
 
412
 
                return -1;
413
 
 
414
 
        }
415
 
 
416
 
        safe_strcpy(path, p, path_len - 1);
417
 
 
418
 
        all_string_sub(path, "/", "\\", 0);
419
 
 
420
 
 decoding:
421
 
        (void) smbc_urldecode(path, path, path_len);
422
 
        (void) smbc_urldecode(server, server, server_len);
423
 
        (void) smbc_urldecode(share, share, share_len);
424
 
        (void) smbc_urldecode(user, user, user_len);
425
 
        (void) smbc_urldecode(password, password, password_len);
426
 
 
427
 
        return 0;
428
 
}
429
 
 
430
 
/*
431
 
 * Verify that the options specified in a URL are valid
432
 
 */
433
 
static int
434
 
smbc_check_options(char *server,
435
 
                   char *share,
436
 
                   char *path,
437
 
                   char *options)
438
 
{
439
 
        DEBUG(4, ("smbc_check_options(): server='%s' share='%s' "
440
 
                  "path='%s' options='%s'\n",
441
 
                  server, share, path, options));
442
 
 
443
 
        /* No options at all is always ok */
444
 
        if (! *options) return 0;
445
 
 
446
 
        /* Currently, we don't support any options. */
447
 
        return -1;
448
 
}
449
 
 
450
 
/*
451
 
 * Convert an SMB error into a UNIX error ...
452
 
 */
453
 
static int
454
 
smbc_errno(SMBCCTX *context,
455
 
           struct cli_state *c)
456
 
{
457
 
        int ret = cli_errno(c);
458
 
        
459
 
        if (cli_is_dos_error(c)) {
460
 
                uint8 eclass;
461
 
                uint32 ecode;
462
 
 
463
 
                cli_dos_error(c, &eclass, &ecode);
464
 
                
465
 
                DEBUG(3,("smbc_error %d %d (0x%x) -> %d\n", 
466
 
                         (int)eclass, (int)ecode, (int)ecode, ret));
467
 
        } else {
468
 
                NTSTATUS status;
469
 
 
470
 
                status = cli_nt_error(c);
471
 
 
472
 
                DEBUG(3,("smbc errno %s -> %d\n",
473
 
                         nt_errstr(status), ret));
474
 
        }
475
 
 
476
 
        return ret;
477
 
}
478
 
 
479
 
/* 
480
 
 * Check a server for being alive and well.
481
 
 * returns 0 if the server is in shape. Returns 1 on error 
482
 
 * 
483
 
 * Also useable outside libsmbclient to enable external cache
484
 
 * to do some checks too.
485
 
 */
486
 
static int
487
 
smbc_check_server(SMBCCTX * context,
488
 
                  SMBCSRV * server) 
489
 
{
490
 
        if ( send_keepalive(server->cli->fd) == False )
491
 
                return 1;
492
 
 
493
 
        /* connection is ok */
494
 
        return 0;
495
 
}
496
 
 
497
 
/* 
498
 
 * Remove a server from the cached server list it's unused.
499
 
 * On success, 0 is returned. 1 is returned if the server could not be removed.
500
 
 * 
501
 
 * Also useable outside libsmbclient
502
 
 */
503
 
int
504
 
smbc_remove_unused_server(SMBCCTX * context,
505
 
                          SMBCSRV * srv)
506
 
{
507
 
        SMBCFILE * file;
508
 
 
509
 
        /* are we being fooled ? */
510
 
        if (!context || !context->internal ||
511
 
            !context->internal->_initialized || !srv) return 1;
512
 
 
513
 
        
514
 
        /* Check all open files/directories for a relation with this server */
515
 
        for (file = context->internal->_files; file; file=file->next) {
516
 
                if (file->srv == srv) {
517
 
                        /* Still used */
518
 
                        DEBUG(3, ("smbc_remove_usused_server: "
519
 
                                  "%p still used by %p.\n", 
520
 
                                  srv, file));
521
 
                        return 1;
522
 
                }
523
 
        }
524
 
 
525
 
        DLIST_REMOVE(context->internal->_servers, srv);
526
 
 
527
 
        cli_shutdown(srv->cli);
528
 
        srv->cli = NULL;
529
 
 
530
 
        DEBUG(3, ("smbc_remove_usused_server: %p removed.\n", srv));
531
 
 
532
 
        context->callbacks.remove_cached_srv_fn(context, srv);
533
 
 
534
 
        SAFE_FREE(srv);
535
 
        
536
 
        return 0;
537
 
}
538
 
 
539
 
static SMBCSRV *
540
 
find_server(SMBCCTX *context,
541
 
            const char *server,
542
 
            const char *share,
543
 
            fstring workgroup,
544
 
            fstring username,
545
 
            fstring password)
546
 
{
547
 
        SMBCSRV *srv;
548
 
        int auth_called = 0;
549
 
        
550
 
 check_server_cache:
551
 
 
552
 
        srv = context->callbacks.get_cached_srv_fn(context, server, share, 
553
 
                                                   workgroup, username);
554
 
 
555
 
        if (!auth_called && !srv && (!username[0] || !password[0])) {
556
 
                if (context->internal->_auth_fn_with_context != NULL) {
557
 
                         context->internal->_auth_fn_with_context(
558
 
                                context,
559
 
                                server, share,
560
 
                                workgroup, sizeof(fstring),
561
 
                                username, sizeof(fstring),
562
 
                                password, sizeof(fstring));
563
 
                } else {
564
 
                        context->callbacks.auth_fn(
565
 
                                server, share,
566
 
                                workgroup, sizeof(fstring),
567
 
                                username, sizeof(fstring),
568
 
                                password, sizeof(fstring));
569
 
                }
570
 
 
571
 
                /*
572
 
                 * However, smbc_auth_fn may have picked up info relating to
573
 
                 * an existing connection, so try for an existing connection
574
 
                 * again ...
575
 
                 */
576
 
                auth_called = 1;
577
 
                goto check_server_cache;
578
 
                
579
 
        }
580
 
        
581
 
        if (srv) {
582
 
                if (context->callbacks.check_server_fn(context, srv)) {
583
 
                        /*
584
 
                         * This server is no good anymore 
585
 
                         * Try to remove it and check for more possible
586
 
                         * servers in the cache
587
 
                         */
588
 
                        if (context->callbacks.remove_unused_server_fn(context,
589
 
                                                                       srv)) { 
590
 
                                /*
591
 
                                 * We could not remove the server completely,
592
 
                                 * remove it from the cache so we will not get
593
 
                                 * it again. It will be removed when the last
594
 
                                 * file/dir is closed.
595
 
                                 */
596
 
                                context->callbacks.remove_cached_srv_fn(context,
597
 
                                                                        srv);
598
 
                        }
599
 
                        
600
 
                        /*
601
 
                         * Maybe there are more cached connections to this
602
 
                         * server
603
 
                         */
604
 
                        goto check_server_cache; 
605
 
                }
606
 
 
607
 
                return srv;
608
 
        }
609
 
 
610
 
        return NULL;
611
 
}
612
 
 
613
 
/*
614
 
 * Connect to a server, possibly on an existing connection
615
 
 *
616
 
 * Here, what we want to do is: If the server and username
617
 
 * match an existing connection, reuse that, otherwise, establish a 
618
 
 * new connection.
619
 
 *
620
 
 * If we have to create a new connection, call the auth_fn to get the
621
 
 * info we need, unless the username and password were passed in.
622
 
 */
623
 
 
624
 
static SMBCSRV *
625
 
smbc_server(SMBCCTX *context,
626
 
            BOOL connect_if_not_found,
627
 
            const char *server,
628
 
            const char *share, 
629
 
            fstring workgroup,
630
 
            fstring username, 
631
 
            fstring password)
632
 
{
633
 
        SMBCSRV *srv=NULL;
634
 
        struct cli_state *c;
635
 
        struct nmb_name called, calling;
636
 
        const char *server_n = server;
637
 
        pstring ipenv;
638
 
        struct in_addr ip;
639
 
        int tried_reverse = 0;
640
 
        int port_try_first;
641
 
        int port_try_next;
642
 
        const char *username_used;
643
 
  
644
 
        zero_ip(&ip);
645
 
        ZERO_STRUCT(c);
646
 
 
647
 
        if (server[0] == 0) {
648
 
                errno = EPERM;
649
 
                return NULL;
650
 
        }
651
 
 
652
 
        /* Look for a cached connection */
653
 
        srv = find_server(context, server, share,
654
 
                          workgroup, username, password);
655
 
        
656
 
        /*
657
 
         * If we found a connection and we're only allowed one share per
658
 
         * server...
659
 
         */
660
 
        if (srv && *share != '\0' && context->options.one_share_per_server) {
661
 
 
662
 
                /*
663
 
                 * ... then if there's no current connection to the share,
664
 
                 * connect to it.  find_server(), or rather the function
665
 
                 * pointed to by context->callbacks.get_cached_srv_fn which
666
 
                 * was called by find_server(), will have issued a tree
667
 
                 * disconnect if the requested share is not the same as the
668
 
                 * one that was already connected.
669
 
                 */
670
 
                if (srv->cli->cnum == (uint16) -1) {
671
 
                        /* Ensure we have accurate auth info */
672
 
                        if (context->internal->_auth_fn_with_context != NULL) {
673
 
                                context->internal->_auth_fn_with_context(
674
 
                                        context,
675
 
                                        server, share,
676
 
                                        workgroup, sizeof(fstring),
677
 
                                        username, sizeof(fstring),
678
 
                                        password, sizeof(fstring));
679
 
                        } else {
680
 
                                context->callbacks.auth_fn(
681
 
                                        server, share,
682
 
                                        workgroup, sizeof(fstring),
683
 
                                        username, sizeof(fstring),
684
 
                                        password, sizeof(fstring));
685
 
                        }
686
 
 
687
 
                        if (! cli_send_tconX(srv->cli, share, "?????",
688
 
                                             password, strlen(password)+1)) {
689
 
                        
690
 
                                errno = smbc_errno(context, srv->cli);
691
 
                                cli_shutdown(srv->cli);
692
 
                                srv->cli = NULL;
693
 
                                context->callbacks.remove_cached_srv_fn(context,
694
 
                                                                        srv);
695
 
                                srv = NULL;
696
 
                        }
697
 
 
698
 
                        /*
699
 
                         * Regenerate the dev value since it's based on both
700
 
                         * server and share
701
 
                         */
702
 
                        if (srv) {
703
 
                                srv->dev = (dev_t)(str_checksum(server) ^
704
 
                                                   str_checksum(share));
705
 
                        }
706
 
                }
707
 
        }
708
 
        
709
 
        /* If we have a connection... */
710
 
        if (srv) {
711
 
 
712
 
                /* ... then we're done here.  Give 'em what they came for. */
713
 
                return srv;
714
 
        }
715
 
 
716
 
        /* If we're not asked to connect when a connection doesn't exist... */
717
 
        if (! connect_if_not_found) {
718
 
                /* ... then we're done here. */
719
 
                return NULL;
720
 
        }
721
 
 
722
 
        make_nmb_name(&calling, context->netbios_name, 0x0);
723
 
        make_nmb_name(&called , server, 0x20);
724
 
 
725
 
        DEBUG(4,("smbc_server: server_n=[%s] server=[%s]\n", server_n, server));
726
 
  
727
 
        DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
728
 
 
729
 
 again:
730
 
        slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n);
731
 
 
732
 
        zero_ip(&ip);
733
 
 
734
 
        /* have to open a new connection */
735
 
        if ((c = cli_initialise()) == NULL) {
736
 
                errno = ENOMEM;
737
 
                return NULL;
738
 
        }
739
 
 
740
 
        if (context->flags & SMB_CTX_FLAG_USE_KERBEROS) {
741
 
                c->use_kerberos = True;
742
 
        }
743
 
        if (context->flags & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS) {
744
 
                c->fallback_after_kerberos = True;
745
 
        }
746
 
 
747
 
        c->timeout = context->timeout;
748
 
 
749
 
        /*
750
 
         * Force use of port 139 for first try if share is $IPC, empty, or
751
 
         * null, so browse lists can work
752
 
         */
753
 
        if (share == NULL || *share == '\0' || strcmp(share, "IPC$") == 0) {
754
 
                port_try_first = 139;
755
 
                port_try_next = 445;
756
 
        } else {
757
 
                port_try_first = 445;
758
 
                port_try_next = 139;
759
 
        }
760
 
 
761
 
        c->port = port_try_first;
762
 
 
763
 
        if (!cli_connect(c, server_n, &ip)) {
764
 
 
765
 
                /* First connection attempt failed.  Try alternate port. */
766
 
                c->port = port_try_next;
767
 
 
768
 
                if (!cli_connect(c, server_n, &ip)) {
769
 
                        cli_shutdown(c);
770
 
                        errno = ETIMEDOUT;
771
 
                        return NULL;
772
 
                }
773
 
        }
774
 
 
775
 
        if (!cli_session_request(c, &calling, &called)) {
776
 
                cli_shutdown(c);
777
 
                if (strcmp(called.name, "*SMBSERVER")) {
778
 
                        make_nmb_name(&called , "*SMBSERVER", 0x20);
779
 
                        goto again;
780
 
                } else {  /* Try one more time, but ensure we don't loop */
781
 
 
782
 
                        /* Only try this if server is an IP address ... */
783
 
 
784
 
                        if (is_ipaddress(server) && !tried_reverse) {
785
 
                                fstring remote_name;
786
 
                                struct in_addr rem_ip;
787
 
 
788
 
                                if ((rem_ip.s_addr=inet_addr(server)) == INADDR_NONE) {
789
 
                                        DEBUG(4, ("Could not convert IP address "
790
 
                                                "%s to struct in_addr\n", server));
791
 
                                        errno = ETIMEDOUT;
792
 
                                        return NULL;
793
 
                                }
794
 
 
795
 
                                tried_reverse++; /* Yuck */
796
 
 
797
 
                                if (name_status_find("*", 0, 0, rem_ip, remote_name)) {
798
 
                                        make_nmb_name(&called, remote_name, 0x20);
799
 
                                        goto again;
800
 
                                }
801
 
                        }
802
 
                }
803
 
                errno = ETIMEDOUT;
804
 
                return NULL;
805
 
        }
806
 
  
807
 
        DEBUG(4,(" session request ok\n"));
808
 
  
809
 
        if (!cli_negprot(c)) {
810
 
                cli_shutdown(c);
811
 
                errno = ETIMEDOUT;
812
 
                return NULL;
813
 
        }
814
 
 
815
 
        username_used = username;
816
 
 
817
 
        if (!cli_session_setup(c, username_used, 
818
 
                               password, strlen(password),
819
 
                               password, strlen(password),
820
 
                               workgroup)) {
821
 
                
822
 
                /* Failed.  Try an anonymous login, if allowed by flags. */
823
 
                username_used = "";
824
 
 
825
 
                if ((context->flags & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON) ||
826
 
                     !cli_session_setup(c, username_used,
827
 
                                        password, 1,
828
 
                                        password, 0,
829
 
                                        workgroup)) {
830
 
 
831
 
                        cli_shutdown(c);
832
 
                        errno = EPERM;
833
 
                        return NULL;
834
 
                }
835
 
        }
836
 
 
837
 
        DEBUG(4,(" session setup ok\n"));
838
 
 
839
 
        if (!cli_send_tconX(c, share, "?????",
840
 
                            password, strlen(password)+1)) {
841
 
                errno = smbc_errno(context, c);
842
 
                cli_shutdown(c);
843
 
                return NULL;
844
 
        }
845
 
  
846
 
        DEBUG(4,(" tconx ok\n"));
847
 
  
848
 
        /*
849
 
         * Ok, we have got a nice connection
850
 
         * Let's allocate a server structure.
851
 
         */
852
 
 
853
 
        srv = SMB_MALLOC_P(SMBCSRV);
854
 
        if (!srv) {
855
 
                errno = ENOMEM;
856
 
                goto failed;
857
 
        }
858
 
 
859
 
        ZERO_STRUCTP(srv);
860
 
        srv->cli = c;
861
 
        srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
862
 
        srv->no_pathinfo = False;
863
 
        srv->no_pathinfo2 = False;
864
 
        srv->no_nt_session = False;
865
 
 
866
 
        /* now add it to the cache (internal or external)  */
867
 
        /* Let the cache function set errno if it wants to */
868
 
        errno = 0;
869
 
        if (context->callbacks.add_cached_srv_fn(context, srv, server, share, workgroup, username)) {
870
 
                int saved_errno = errno;
871
 
                DEBUG(3, (" Failed to add server to cache\n"));
872
 
                errno = saved_errno;
873
 
                if (errno == 0) {
874
 
                        errno = ENOMEM;
875
 
                }
876
 
                goto failed;
877
 
        }
878
 
        
879
 
        DEBUG(2, ("Server connect ok: //%s/%s: %p\n", 
880
 
                  server, share, srv));
881
 
 
882
 
        DLIST_ADD(context->internal->_servers, srv);
883
 
        return srv;
884
 
 
885
 
 failed:
886
 
        cli_shutdown(c);
887
 
        if (!srv) {
888
 
                return NULL;
889
 
        }
890
 
  
891
 
        SAFE_FREE(srv);
892
 
        return NULL;
893
 
}
894
 
 
895
 
/*
896
 
 * Connect to a server for getting/setting attributes, possibly on an existing
897
 
 * connection.  This works similarly to smbc_server().
898
 
 */
899
 
static SMBCSRV *
900
 
smbc_attr_server(SMBCCTX *context,
901
 
                 const char *server,
902
 
                 const char *share, 
903
 
                 fstring workgroup,
904
 
                 fstring username,
905
 
                 fstring password,
906
 
                 POLICY_HND *pol)
907
 
{
908
 
        struct in_addr ip;
909
 
        struct cli_state *ipc_cli;
910
 
        struct rpc_pipe_client *pipe_hnd;
911
 
        NTSTATUS nt_status;
912
 
        SMBCSRV *ipc_srv=NULL;
913
 
 
914
 
        /*
915
 
         * See if we've already created this special connection.  Reference
916
 
         * our "special" share name '*IPC$', which is an impossible real share
917
 
         * name due to the leading asterisk.
918
 
         */
919
 
        ipc_srv = find_server(context, server, "*IPC$",
920
 
                              workgroup, username, password);
921
 
        if (!ipc_srv) {
922
 
 
923
 
                /* We didn't find a cached connection.  Get the password */
924
 
                if (*password == '\0') {
925
 
                        /* ... then retrieve it now. */
926
 
                        if (context->internal->_auth_fn_with_context != NULL) {
927
 
                                context->internal->_auth_fn_with_context(
928
 
                                        context,
929
 
                                        server, share,
930
 
                                        workgroup, sizeof(fstring),
931
 
                                        username, sizeof(fstring),
932
 
                                        password, sizeof(fstring));
933
 
                        } else {
934
 
                                context->callbacks.auth_fn(
935
 
                                        server, share,
936
 
                                        workgroup, sizeof(fstring),
937
 
                                        username, sizeof(fstring),
938
 
                                        password, sizeof(fstring));
939
 
                        }
940
 
                }
941
 
        
942
 
                zero_ip(&ip);
943
 
                nt_status = cli_full_connection(&ipc_cli,
944
 
                                                global_myname(), server, 
945
 
                                                &ip, 0, "IPC$", "?????",  
946
 
                                                username, workgroup,
947
 
                                                password, 0,
948
 
                                                Undefined, NULL);
949
 
                if (! NT_STATUS_IS_OK(nt_status)) {
950
 
                        DEBUG(1,("cli_full_connection failed! (%s)\n",
951
 
                                 nt_errstr(nt_status)));
952
 
                        errno = ENOTSUP;
953
 
                        return NULL;
954
 
                }
955
 
 
956
 
                ipc_srv = SMB_MALLOC_P(SMBCSRV);
957
 
                if (!ipc_srv) {
958
 
                        errno = ENOMEM;
959
 
                        cli_shutdown(ipc_cli);
960
 
                        return NULL;
961
 
                }
962
 
 
963
 
                ZERO_STRUCTP(ipc_srv);
964
 
                ipc_srv->cli = ipc_cli;
965
 
 
966
 
                if (pol) {
967
 
                        pipe_hnd = cli_rpc_pipe_open_noauth(ipc_srv->cli,
968
 
                                                            PI_LSARPC,
969
 
                                                            &nt_status);
970
 
                        if (!pipe_hnd) {
971
 
                                DEBUG(1, ("cli_nt_session_open fail!\n"));
972
 
                                errno = ENOTSUP;
973
 
                                cli_shutdown(ipc_srv->cli);
974
 
                                free(ipc_srv);
975
 
                                return NULL;
976
 
                        }
977
 
 
978
 
                        /*
979
 
                         * Some systems don't support
980
 
                         * SEC_RIGHTS_MAXIMUM_ALLOWED, but NT sends 0x2000000
981
 
                         * so we might as well do it too.
982
 
                         */
983
 
        
984
 
                        nt_status = rpccli_lsa_open_policy(
985
 
                                pipe_hnd,
986
 
                                ipc_srv->cli->mem_ctx,
987
 
                                True, 
988
 
                                GENERIC_EXECUTE_ACCESS,
989
 
                                pol);
990
 
        
991
 
                        if (!NT_STATUS_IS_OK(nt_status)) {
992
 
                                errno = smbc_errno(context, ipc_srv->cli);
993
 
                                cli_shutdown(ipc_srv->cli);
994
 
                                return NULL;
995
 
                        }
996
 
                }
997
 
 
998
 
                /* now add it to the cache (internal or external) */
999
 
 
1000
 
                errno = 0;      /* let cache function set errno if it likes */
1001
 
                if (context->callbacks.add_cached_srv_fn(context, ipc_srv,
1002
 
                                                         server,
1003
 
                                                         "*IPC$",
1004
 
                                                         workgroup,
1005
 
                                                         username)) {
1006
 
                        DEBUG(3, (" Failed to add server to cache\n"));
1007
 
                        if (errno == 0) {
1008
 
                                errno = ENOMEM;
1009
 
                        }
1010
 
                        cli_shutdown(ipc_srv->cli);
1011
 
                        free(ipc_srv);
1012
 
                        return NULL;
1013
 
                }
1014
 
 
1015
 
                DLIST_ADD(context->internal->_servers, ipc_srv);
1016
 
        }
1017
 
 
1018
 
        return ipc_srv;
1019
 
}
1020
 
 
1021
 
/*
1022
 
 * Routine to open() a file ...
1023
 
 */
1024
 
 
1025
 
static SMBCFILE *
1026
 
smbc_open_ctx(SMBCCTX *context,
1027
 
              const char *fname,
1028
 
              int flags,
1029
 
              mode_t mode)
1030
 
{
1031
 
        fstring server, share, user, password, workgroup;
1032
 
        pstring path;
1033
 
        pstring targetpath;
1034
 
        struct cli_state *targetcli;
1035
 
        SMBCSRV *srv   = NULL;
1036
 
        SMBCFILE *file = NULL;
1037
 
        int fd;
1038
 
 
1039
 
        if (!context || !context->internal ||
1040
 
            !context->internal->_initialized) {
1041
 
 
1042
 
                errno = EINVAL;  /* Best I can think of ... */
1043
 
                return NULL;
1044
 
 
1045
 
        }
1046
 
 
1047
 
        if (!fname) {
1048
 
 
1049
 
                errno = EINVAL;
1050
 
                return NULL;
1051
 
 
1052
 
        }
1053
 
 
1054
 
        if (smbc_parse_path(context, fname,
1055
 
                            workgroup, sizeof(workgroup),
1056
 
                            server, sizeof(server),
1057
 
                            share, sizeof(share),
1058
 
                            path, sizeof(path),
1059
 
                            user, sizeof(user),
1060
 
                            password, sizeof(password),
1061
 
                            NULL, 0)) {
1062
 
                errno = EINVAL;
1063
 
                return NULL;
1064
 
        }
1065
 
 
1066
 
        if (user[0] == (char)0) fstrcpy(user, context->user);
1067
 
 
1068
 
        srv = smbc_server(context, True,
1069
 
                          server, share, workgroup, user, password);
1070
 
 
1071
 
        if (!srv) {
1072
 
 
1073
 
                if (errno == EPERM) errno = EACCES;
1074
 
                return NULL;  /* smbc_server sets errno */
1075
 
    
1076
 
        }
1077
 
 
1078
 
        /* Hmmm, the test for a directory is suspect here ... FIXME */
1079
 
 
1080
 
        if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') {
1081
 
    
1082
 
                fd = -1;
1083
 
 
1084
 
        }
1085
 
        else {
1086
 
          
1087
 
                file = SMB_MALLOC_P(SMBCFILE);
1088
 
 
1089
 
                if (!file) {
1090
 
 
1091
 
                        errno = ENOMEM;
1092
 
                        return NULL;
1093
 
 
1094
 
                }
1095
 
 
1096
 
                ZERO_STRUCTP(file);
1097
 
 
1098
 
                /*d_printf(">>>open: resolving %s\n", path);*/
1099
 
                if (!cli_resolve_path( "", srv->cli, path, &targetcli, targetpath))
1100
 
                {
1101
 
                        d_printf("Could not resolve %s\n", path);
1102
 
                        SAFE_FREE(file);
1103
 
                        return NULL;
1104
 
                }
1105
 
                /*d_printf(">>>open: resolved %s as %s\n", path, targetpath);*/
1106
 
                
1107
 
                if ( targetcli->dfsroot )
1108
 
                {
1109
 
                        pstring temppath;
1110
 
                        pstrcpy(temppath, targetpath);
1111
 
                        cli_dfs_make_full_path( targetpath, targetcli->desthost, targetcli->share, temppath);
1112
 
                }
1113
 
                
1114
 
                if ((fd = cli_open(targetcli, targetpath, flags, DENY_NONE)) < 0) {
1115
 
 
1116
 
                        /* Handle the error ... */
1117
 
 
1118
 
                        SAFE_FREE(file);
1119
 
                        errno = smbc_errno(context, targetcli);
1120
 
                        return NULL;
1121
 
 
1122
 
                }
1123
 
 
1124
 
                /* Fill in file struct */
1125
 
 
1126
 
                file->cli_fd  = fd;
1127
 
                file->fname   = SMB_STRDUP(fname);
1128
 
                file->srv     = srv;
1129
 
                file->offset  = 0;
1130
 
                file->file    = True;
1131
 
 
1132
 
                DLIST_ADD(context->internal->_files, file);
1133
 
 
1134
 
                /*
1135
 
                 * If the file was opened in O_APPEND mode, all write
1136
 
                 * operations should be appended to the file.  To do that,
1137
 
                 * though, using this protocol, would require a getattrE()
1138
 
                 * call for each and every write, to determine where the end
1139
 
                 * of the file is. (There does not appear to be an append flag
1140
 
                 * in the protocol.)  Rather than add all of that overhead of
1141
 
                 * retrieving the current end-of-file offset prior to each
1142
 
                 * write operation, we'll assume that most append operations
1143
 
                 * will continuously write, so we'll just set the offset to
1144
 
                 * the end of the file now and hope that's adequate.
1145
 
                 *
1146
 
                 * Note to self: If this proves inadequate, and O_APPEND
1147
 
                 * should, in some cases, be forced for each write, add a
1148
 
                 * field in the context options structure, for
1149
 
                 * "strict_append_mode" which would select between the current
1150
 
                 * behavior (if FALSE) or issuing a getattrE() prior to each
1151
 
                 * write and forcing the write to the end of the file (if
1152
 
                 * TRUE).  Adding that capability will likely require adding
1153
 
                 * an "append" flag into the _SMBCFILE structure to track
1154
 
                 * whether a file was opened in O_APPEND mode.  -- djl
1155
 
                 */
1156
 
                if (flags & O_APPEND) {
1157
 
                        if (smbc_lseek_ctx(context, file, 0, SEEK_END) < 0) {
1158
 
                                (void) smbc_close_ctx(context, file);
1159
 
                                errno = ENXIO;
1160
 
                                return NULL;
1161
 
                        }
1162
 
                }
1163
 
 
1164
 
                return file;
1165
 
 
1166
 
        }
1167
 
 
1168
 
        /* Check if opendir needed ... */
1169
 
 
1170
 
        if (fd == -1) {
1171
 
                int eno = 0;
1172
 
 
1173
 
                eno = smbc_errno(context, srv->cli);
1174
 
                file = context->opendir(context, fname);
1175
 
                if (!file) errno = eno;
1176
 
                return file;
1177
 
 
1178
 
        }
1179
 
 
1180
 
        errno = EINVAL; /* FIXME, correct errno ? */
1181
 
        return NULL;
1182
 
 
1183
 
}
1184
 
 
1185
 
/*
1186
 
 * Routine to create a file 
1187
 
 */
1188
 
 
1189
 
static int creat_bits = O_WRONLY | O_CREAT | O_TRUNC; /* FIXME: Do we need this */
1190
 
 
1191
 
static SMBCFILE *
1192
 
smbc_creat_ctx(SMBCCTX *context,
1193
 
               const char *path,
1194
 
               mode_t mode)
1195
 
{
1196
 
 
1197
 
        if (!context || !context->internal ||
1198
 
            !context->internal->_initialized) {
1199
 
 
1200
 
                errno = EINVAL;
1201
 
                return NULL;
1202
 
 
1203
 
        }
1204
 
 
1205
 
        return smbc_open_ctx(context, path, creat_bits, mode);
1206
 
}
1207
 
 
1208
 
/*
1209
 
 * Routine to read() a file ...
1210
 
 */
1211
 
 
1212
 
static ssize_t
1213
 
smbc_read_ctx(SMBCCTX *context,
1214
 
              SMBCFILE *file,
1215
 
              void *buf,
1216
 
              size_t count)
1217
 
{
1218
 
        int ret;
1219
 
        fstring server, share, user, password;
1220
 
        pstring path, targetpath;
1221
 
        struct cli_state *targetcli;
1222
 
 
1223
 
        /*
1224
 
         * offset:
1225
 
         *
1226
 
         * Compiler bug (possibly) -- gcc (GCC) 3.3.5 (Debian 1:3.3.5-2) --
1227
 
         * appears to pass file->offset (which is type off_t) differently than
1228
 
         * a local variable of type off_t.  Using local variable "offset" in
1229
 
         * the call to cli_read() instead of file->offset fixes a problem
1230
 
         * retrieving data at an offset greater than 4GB.
1231
 
         */
1232
 
        off_t offset;
1233
 
 
1234
 
        if (!context || !context->internal ||
1235
 
            !context->internal->_initialized) {
1236
 
 
1237
 
                errno = EINVAL;
1238
 
                return -1;
1239
 
 
1240
 
        }
1241
 
 
1242
 
        DEBUG(4, ("smbc_read(%p, %d)\n", file, (int)count));
1243
 
 
1244
 
        if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
1245
 
 
1246
 
                errno = EBADF;
1247
 
                return -1;
1248
 
 
1249
 
        }
1250
 
 
1251
 
        offset = file->offset;
1252
 
 
1253
 
        /* Check that the buffer exists ... */
1254
 
 
1255
 
        if (buf == NULL) {
1256
 
 
1257
 
                errno = EINVAL;
1258
 
                return -1;
1259
 
 
1260
 
        }
1261
 
 
1262
 
        /*d_printf(">>>read: parsing %s\n", file->fname);*/
1263
 
        if (smbc_parse_path(context, file->fname,
1264
 
                            NULL, 0,
1265
 
                            server, sizeof(server),
1266
 
                            share, sizeof(share),
1267
 
                            path, sizeof(path),
1268
 
                            user, sizeof(user),
1269
 
                            password, sizeof(password),
1270
 
                            NULL, 0)) {
1271
 
                errno = EINVAL;
1272
 
                return -1;
1273
 
        }
1274
 
        
1275
 
        /*d_printf(">>>read: resolving %s\n", path);*/
1276
 
        if (!cli_resolve_path("", file->srv->cli, path,
1277
 
                              &targetcli, targetpath))
1278
 
        {
1279
 
                d_printf("Could not resolve %s\n", path);
1280
 
                return -1;
1281
 
        }
1282
 
        /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/
1283
 
        
1284
 
        ret = cli_read(targetcli, file->cli_fd, buf, offset, count);
1285
 
 
1286
 
        if (ret < 0) {
1287
 
 
1288
 
                errno = smbc_errno(context, targetcli);
1289
 
                return -1;
1290
 
 
1291
 
        }
1292
 
 
1293
 
        file->offset += ret;
1294
 
 
1295
 
        DEBUG(4, ("  --> %d\n", ret));
1296
 
 
1297
 
        return ret;  /* Success, ret bytes of data ... */
1298
 
 
1299
 
}
1300
 
 
1301
 
/*
1302
 
 * Routine to write() a file ...
1303
 
 */
1304
 
 
1305
 
static ssize_t
1306
 
smbc_write_ctx(SMBCCTX *context,
1307
 
               SMBCFILE *file,
1308
 
               void *buf,
1309
 
               size_t count)
1310
 
{
1311
 
        int ret;
1312
 
        off_t offset;
1313
 
        fstring server, share, user, password;
1314
 
        pstring path, targetpath;
1315
 
        struct cli_state *targetcli;
1316
 
 
1317
 
        /* First check all pointers before dereferencing them */
1318
 
        
1319
 
        if (!context || !context->internal ||
1320
 
            !context->internal->_initialized) {
1321
 
 
1322
 
                errno = EINVAL;
1323
 
                return -1;
1324
 
 
1325
 
        }
1326
 
 
1327
 
        if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
1328
 
 
1329
 
                errno = EBADF;
1330
 
                return -1;
1331
 
    
1332
 
        }
1333
 
 
1334
 
        /* Check that the buffer exists ... */
1335
 
 
1336
 
        if (buf == NULL) {
1337
 
 
1338
 
                errno = EINVAL;
1339
 
                return -1;
1340
 
 
1341
 
        }
1342
 
 
1343
 
        offset = file->offset; /* See "offset" comment in smbc_read_ctx() */
1344
 
 
1345
 
        /*d_printf(">>>write: parsing %s\n", file->fname);*/
1346
 
        if (smbc_parse_path(context, file->fname,
1347
 
                            NULL, 0,
1348
 
                            server, sizeof(server),
1349
 
                            share, sizeof(share),
1350
 
                            path, sizeof(path),
1351
 
                            user, sizeof(user),
1352
 
                            password, sizeof(password),
1353
 
                            NULL, 0)) {
1354
 
                errno = EINVAL;
1355
 
                return -1;
1356
 
        }
1357
 
        
1358
 
        /*d_printf(">>>write: resolving %s\n", path);*/
1359
 
        if (!cli_resolve_path("", file->srv->cli, path,
1360
 
                              &targetcli, targetpath))
1361
 
        {
1362
 
                d_printf("Could not resolve %s\n", path);
1363
 
                return -1;
1364
 
        }
1365
 
        /*d_printf(">>>write: resolved path as %s\n", targetpath);*/
1366
 
 
1367
 
 
1368
 
        ret = cli_write(targetcli, file->cli_fd, 0, buf, offset, count);
1369
 
 
1370
 
        if (ret <= 0) {
1371
 
 
1372
 
                errno = smbc_errno(context, targetcli);
1373
 
                return -1;
1374
 
 
1375
 
        }
1376
 
 
1377
 
        file->offset += ret;
1378
 
 
1379
 
        return ret;  /* Success, 0 bytes of data ... */
1380
 
}
1381
 
 
1382
 
/*
1383
 
 * Routine to close() a file ...
1384
 
 */
1385
 
 
1386
 
static int
1387
 
smbc_close_ctx(SMBCCTX *context,
1388
 
               SMBCFILE *file)
1389
 
{
1390
 
        SMBCSRV *srv; 
1391
 
        fstring server, share, user, password;
1392
 
        pstring path, targetpath;
1393
 
        struct cli_state *targetcli;
1394
 
 
1395
 
        if (!context || !context->internal ||
1396
 
            !context->internal->_initialized) {
1397
 
 
1398
 
                errno = EINVAL;
1399
 
                return -1;
1400
 
 
1401
 
        }
1402
 
 
1403
 
        if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
1404
 
   
1405
 
                errno = EBADF;
1406
 
                return -1;
1407
 
 
1408
 
        }
1409
 
 
1410
 
        /* IS a dir ... */
1411
 
        if (!file->file) {
1412
 
                
1413
 
                return context->closedir(context, file);
1414
 
 
1415
 
        }
1416
 
 
1417
 
        /*d_printf(">>>close: parsing %s\n", file->fname);*/
1418
 
        if (smbc_parse_path(context, file->fname,
1419
 
                            NULL, 0,
1420
 
                            server, sizeof(server),
1421
 
                            share, sizeof(share),
1422
 
                            path, sizeof(path),
1423
 
                            user, sizeof(user),
1424
 
                            password, sizeof(password),
1425
 
                            NULL, 0)) {
1426
 
                errno = EINVAL;
1427
 
                return -1;
1428
 
        }
1429
 
        
1430
 
        /*d_printf(">>>close: resolving %s\n", path);*/
1431
 
        if (!cli_resolve_path("", file->srv->cli, path,
1432
 
                              &targetcli, targetpath))
1433
 
        {
1434
 
                d_printf("Could not resolve %s\n", path);
1435
 
                return -1;
1436
 
        }
1437
 
        /*d_printf(">>>close: resolved path as %s\n", targetpath);*/
1438
 
 
1439
 
        if (!cli_close(targetcli, file->cli_fd)) {
1440
 
 
1441
 
                DEBUG(3, ("cli_close failed on %s. purging server.\n", 
1442
 
                          file->fname));
1443
 
                /* Deallocate slot and remove the server 
1444
 
                 * from the server cache if unused */
1445
 
                errno = smbc_errno(context, targetcli);
1446
 
                srv = file->srv;
1447
 
                DLIST_REMOVE(context->internal->_files, file);
1448
 
                SAFE_FREE(file->fname);
1449
 
                SAFE_FREE(file);
1450
 
                context->callbacks.remove_unused_server_fn(context, srv);
1451
 
 
1452
 
                return -1;
1453
 
 
1454
 
        }
1455
 
 
1456
 
        DLIST_REMOVE(context->internal->_files, file);
1457
 
        SAFE_FREE(file->fname);
1458
 
        SAFE_FREE(file);
1459
 
 
1460
 
        return 0;
1461
 
}
1462
 
 
1463
 
/*
1464
 
 * Get info from an SMB server on a file. Use a qpathinfo call first
1465
 
 * and if that fails, use getatr, as Win95 sometimes refuses qpathinfo
1466
 
 */
1467
 
static BOOL
1468
 
smbc_getatr(SMBCCTX * context,
1469
 
            SMBCSRV *srv,
1470
 
            char *path, 
1471
 
            uint16 *mode,
1472
 
            SMB_OFF_T *size, 
1473
 
            time_t *c_time,
1474
 
            time_t *a_time,
1475
 
            time_t *m_time,
1476
 
            SMB_INO_T *ino)
1477
 
{
1478
 
        pstring fixedpath;
1479
 
        pstring targetpath;
1480
 
        struct cli_state *targetcli;
1481
 
 
1482
 
        if (!context || !context->internal ||
1483
 
            !context->internal->_initialized) {
1484
 
 
1485
 
                errno = EINVAL;
1486
 
                return -1;
1487
 
 
1488
 
        }
1489
 
 
1490
 
        /* path fixup for . and .. */
1491
 
        if (strequal(path, ".") || strequal(path, ".."))
1492
 
                pstrcpy(fixedpath, "\\");
1493
 
        else
1494
 
        {
1495
 
                pstrcpy(fixedpath, path);
1496
 
                trim_string(fixedpath, NULL, "\\..");
1497
 
                trim_string(fixedpath, NULL, "\\.");
1498
 
        }
1499
 
        DEBUG(4,("smbc_getatr: sending qpathinfo\n"));
1500
 
  
1501
 
        if (!cli_resolve_path( "", srv->cli, fixedpath, &targetcli, targetpath))
1502
 
        {
1503
 
                d_printf("Couldn't resolve %s\n", path);
1504
 
                return False;
1505
 
        }
1506
 
        
1507
 
        if ( targetcli->dfsroot )
1508
 
        {
1509
 
                pstring temppath;
1510
 
                pstrcpy(temppath, targetpath);
1511
 
                cli_dfs_make_full_path(targetpath, targetcli->desthost,
1512
 
                                       targetcli->share, temppath);
1513
 
        }
1514
 
  
1515
 
        if (!srv->no_pathinfo2 &&
1516
 
            cli_qpathinfo2(targetcli, targetpath,
1517
 
                           c_time, a_time, m_time, NULL, size, mode, ino)) {
1518
 
            return True;
1519
 
        }
1520
 
 
1521
 
        /* if this is NT then don't bother with the getatr */
1522
 
        if (targetcli->capabilities & CAP_NT_SMBS) {
1523
 
                errno = EPERM;
1524
 
                return False;
1525
 
        }
1526
 
 
1527
 
        if (cli_getatr(targetcli, targetpath, mode, size, m_time)) {
1528
 
                if (m_time != NULL) {
1529
 
                        if (a_time != NULL) *a_time = *m_time;
1530
 
                        if (c_time != NULL) *c_time = *m_time;
1531
 
                }
1532
 
                srv->no_pathinfo2 = True;
1533
 
                return True;
1534
 
        }
1535
 
 
1536
 
        errno = EPERM;
1537
 
        return False;
1538
 
 
1539
 
}
1540
 
 
1541
 
/*
1542
 
 * Set file info on an SMB server.  Use setpathinfo call first.  If that
1543
 
 * fails, use setattrE..
1544
 
 *
1545
 
 * Access and modification time parameters are always used and must be
1546
 
 * provided.  Create time, if zero, will be determined from the actual create
1547
 
 * time of the file.  If non-zero, the create time will be set as well.
1548
 
 *
1549
 
 * "mode" (attributes) parameter may be set to -1 if it is not to be set.
1550
 
 */
1551
 
static BOOL
1552
 
smbc_setatr(SMBCCTX * context, SMBCSRV *srv, char *path, 
1553
 
            time_t c_time, time_t a_time, time_t m_time,
1554
 
            uint16 mode)
1555
 
{
1556
 
        int fd;
1557
 
        int ret;
1558
 
 
1559
 
        /*
1560
 
         * First, try setpathinfo (if qpathinfo succeeded), for it is the
1561
 
         * modern function for "new code" to be using, and it works given a
1562
 
         * filename rather than requiring that the file be opened to have its
1563
 
         * attributes manipulated.
1564
 
         */
1565
 
        if (srv->no_pathinfo ||
1566
 
            ! cli_setpathinfo(srv->cli, path, c_time, a_time, m_time, mode)) {
1567
 
 
1568
 
                /*
1569
 
                 * setpathinfo is not supported; go to plan B. 
1570
 
                 *
1571
 
                 * cli_setatr() does not work on win98, and it also doesn't
1572
 
                 * support setting the access time (only the modification
1573
 
                 * time), so in all cases, we open the specified file and use
1574
 
                 * cli_setattrE() which should work on all OS versions, and
1575
 
                 * supports both times.
1576
 
                 */
1577
 
 
1578
 
                /* Don't try {q,set}pathinfo() again, with this server */
1579
 
                srv->no_pathinfo = True;
1580
 
 
1581
 
                /* Open the file */
1582
 
                if ((fd = cli_open(srv->cli, path, O_RDWR, DENY_NONE)) < 0) {
1583
 
 
1584
 
                        errno = smbc_errno(context, srv->cli);
1585
 
                        return -1;
1586
 
                }
1587
 
 
1588
 
                /*
1589
 
                 * Get the creat time of the file (if it wasn't provided).
1590
 
                 * We'll need it in the set call
1591
 
                 */
1592
 
                if (c_time == 0) {
1593
 
                        ret = cli_getattrE(srv->cli, fd,
1594
 
                                           NULL, NULL,
1595
 
                                           &c_time, NULL, NULL);
1596
 
                } else {
1597
 
                        ret = True;
1598
 
                }
1599
 
                    
1600
 
                /* If we got create time, set times */
1601
 
                if (ret) {
1602
 
                        /* Some OS versions don't support create time */
1603
 
                        if (c_time == 0 || c_time == -1) {
1604
 
                                c_time = time(NULL);
1605
 
                        }
1606
 
 
1607
 
                        /*
1608
 
                         * For sanity sake, since there is no POSIX function
1609
 
                         * to set the create time of a file, if the existing
1610
 
                         * create time is greater than either of access time
1611
 
                         * or modification time, set create time to the
1612
 
                         * smallest of those.  This ensure that the create
1613
 
                         * time of a file is never greater than its last
1614
 
                         * access or modification time.
1615
 
                         */
1616
 
                        if (c_time > a_time) c_time = a_time;
1617
 
                        if (c_time > m_time) c_time = m_time;
1618
 
                        
1619
 
                        /* Set the new attributes */
1620
 
                        ret = cli_setattrE(srv->cli, fd,
1621
 
                                           c_time, a_time, m_time);
1622
 
                        cli_close(srv->cli, fd);
1623
 
                }
1624
 
 
1625
 
                /*
1626
 
                 * Unfortunately, setattrE() doesn't have a provision for
1627
 
                 * setting the access mode (attributes).  We'll have to try
1628
 
                 * cli_setatr() for that, and with only this parameter, it
1629
 
                 * seems to work on win98.
1630
 
                 */
1631
 
                if (ret && mode != (uint16) -1) {
1632
 
                        ret = cli_setatr(srv->cli, path, mode, 0);
1633
 
                }
1634
 
 
1635
 
                if (! ret) {
1636
 
                        errno = smbc_errno(context, srv->cli);
1637
 
                        return False;
1638
 
                }
1639
 
        }
1640
 
 
1641
 
        return True;
1642
 
}
1643
 
 
1644
 
 /*
1645
 
  * Routine to unlink() a file
1646
 
  */
1647
 
 
1648
 
static int
1649
 
smbc_unlink_ctx(SMBCCTX *context,
1650
 
                const char *fname)
1651
 
{
1652
 
        fstring server, share, user, password, workgroup;
1653
 
        pstring path, targetpath;
1654
 
        struct cli_state *targetcli;
1655
 
        SMBCSRV *srv = NULL;
1656
 
 
1657
 
        if (!context || !context->internal ||
1658
 
            !context->internal->_initialized) {
1659
 
 
1660
 
                errno = EINVAL;  /* Best I can think of ... */
1661
 
                return -1;
1662
 
 
1663
 
        }
1664
 
 
1665
 
        if (!fname) {
1666
 
 
1667
 
                errno = EINVAL;
1668
 
                return -1;
1669
 
 
1670
 
        }
1671
 
 
1672
 
        if (smbc_parse_path(context, fname,
1673
 
                            workgroup, sizeof(workgroup),
1674
 
                            server, sizeof(server),
1675
 
                            share, sizeof(share),
1676
 
                            path, sizeof(path),
1677
 
                            user, sizeof(user),
1678
 
                            password, sizeof(password),
1679
 
                            NULL, 0)) {
1680
 
                errno = EINVAL;
1681
 
                return -1;
1682
 
        }
1683
 
 
1684
 
        if (user[0] == (char)0) fstrcpy(user, context->user);
1685
 
 
1686
 
        srv = smbc_server(context, True,
1687
 
                          server, share, workgroup, user, password);
1688
 
 
1689
 
        if (!srv) {
1690
 
 
1691
 
                return -1;  /* smbc_server sets errno */
1692
 
 
1693
 
        }
1694
 
 
1695
 
        /*d_printf(">>>unlink: resolving %s\n", path);*/
1696
 
        if (!cli_resolve_path( "", srv->cli, path, &targetcli, targetpath))
1697
 
        {
1698
 
                d_printf("Could not resolve %s\n", path);
1699
 
                return -1;
1700
 
        }
1701
 
        /*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/
1702
 
 
1703
 
        if (!cli_unlink(targetcli, targetpath)) {
1704
 
 
1705
 
                errno = smbc_errno(context, targetcli);
1706
 
 
1707
 
                if (errno == EACCES) { /* Check if the file is a directory */
1708
 
 
1709
 
                        int saverr = errno;
1710
 
                        SMB_OFF_T size = 0;
1711
 
                        uint16 mode = 0;
1712
 
                        time_t m_time = 0, a_time = 0, c_time = 0;
1713
 
                        SMB_INO_T ino = 0;
1714
 
 
1715
 
                        if (!smbc_getatr(context, srv, path, &mode, &size,
1716
 
                                         &c_time, &a_time, &m_time, &ino)) {
1717
 
 
1718
 
                                /* Hmmm, bad error ... What? */
1719
 
 
1720
 
                                errno = smbc_errno(context, targetcli);
1721
 
                                return -1;
1722
 
 
1723
 
                        }
1724
 
                        else {
1725
 
 
1726
 
                                if (IS_DOS_DIR(mode))
1727
 
                                        errno = EISDIR;
1728
 
                                else
1729
 
                                        errno = saverr;  /* Restore this */
1730
 
 
1731
 
                        }
1732
 
                }
1733
 
 
1734
 
                return -1;
1735
 
 
1736
 
        }
1737
 
 
1738
 
        return 0;  /* Success ... */
1739
 
 
1740
 
}
1741
 
 
1742
 
/*
1743
 
 * Routine to rename() a file
1744
 
 */
1745
 
 
1746
 
static int
1747
 
smbc_rename_ctx(SMBCCTX *ocontext,
1748
 
                const char *oname, 
1749
 
                SMBCCTX *ncontext,
1750
 
                const char *nname)
1751
 
{
1752
 
        fstring server1;
1753
 
        fstring share1;
1754
 
        fstring server2;
1755
 
        fstring share2;
1756
 
        fstring user1;
1757
 
        fstring user2;
1758
 
        fstring password1;
1759
 
        fstring password2;
1760
 
        fstring workgroup;
1761
 
        pstring path1;
1762
 
        pstring path2;
1763
 
        pstring targetpath1;
1764
 
        pstring targetpath2;
1765
 
        struct cli_state *targetcli1;
1766
 
        struct cli_state *targetcli2;
1767
 
        SMBCSRV *srv = NULL;
1768
 
 
1769
 
        if (!ocontext || !ncontext || 
1770
 
            !ocontext->internal || !ncontext->internal ||
1771
 
            !ocontext->internal->_initialized || 
1772
 
            !ncontext->internal->_initialized) {
1773
 
 
1774
 
                errno = EINVAL;  /* Best I can think of ... */
1775
 
                return -1;
1776
 
 
1777
 
        }
1778
 
        
1779
 
        if (!oname || !nname) {
1780
 
 
1781
 
                errno = EINVAL;
1782
 
                return -1;
1783
 
 
1784
 
        }
1785
 
        
1786
 
        DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname));
1787
 
 
1788
 
        smbc_parse_path(ocontext, oname,
1789
 
                        workgroup, sizeof(workgroup),
1790
 
                        server1, sizeof(server1),
1791
 
                        share1, sizeof(share1),
1792
 
                        path1, sizeof(path1),
1793
 
                        user1, sizeof(user1),
1794
 
                        password1, sizeof(password1),
1795
 
                        NULL, 0);
1796
 
 
1797
 
        if (user1[0] == (char)0) fstrcpy(user1, ocontext->user);
1798
 
 
1799
 
        smbc_parse_path(ncontext, nname,
1800
 
                        NULL, 0,
1801
 
                        server2, sizeof(server2),
1802
 
                        share2, sizeof(share2),
1803
 
                        path2, sizeof(path2),
1804
 
                        user2, sizeof(user2),
1805
 
                        password2, sizeof(password2),
1806
 
                        NULL, 0);
1807
 
 
1808
 
        if (user2[0] == (char)0) fstrcpy(user2, ncontext->user);
1809
 
 
1810
 
        if (strcmp(server1, server2) || strcmp(share1, share2) ||
1811
 
            strcmp(user1, user2)) {
1812
 
 
1813
 
                /* Can't rename across file systems, or users?? */
1814
 
 
1815
 
                errno = EXDEV;
1816
 
                return -1;
1817
 
 
1818
 
        }
1819
 
 
1820
 
        srv = smbc_server(ocontext, True,
1821
 
                          server1, share1, workgroup, user1, password1);
1822
 
        if (!srv) {
1823
 
 
1824
 
                return -1;
1825
 
 
1826
 
        }
1827
 
 
1828
 
        /*d_printf(">>>rename: resolving %s\n", path1);*/
1829
 
        if (!cli_resolve_path( "", srv->cli, path1, &targetcli1, targetpath1))
1830
 
        {
1831
 
                d_printf("Could not resolve %s\n", path1);
1832
 
                return -1;
1833
 
        }
1834
 
        /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/
1835
 
        /*d_printf(">>>rename: resolving %s\n", path2);*/
1836
 
        if (!cli_resolve_path( "", srv->cli, path2, &targetcli2, targetpath2))
1837
 
        {
1838
 
                d_printf("Could not resolve %s\n", path2);
1839
 
                return -1;
1840
 
        }
1841
 
        /*d_printf(">>>rename: resolved path as %s\n", targetpath2);*/
1842
 
        
1843
 
        if (strcmp(targetcli1->desthost, targetcli2->desthost) ||
1844
 
            strcmp(targetcli1->share, targetcli2->share))
1845
 
        {
1846
 
                /* can't rename across file systems */
1847
 
                
1848
 
                errno = EXDEV;
1849
 
                return -1;
1850
 
        }
1851
 
 
1852
 
        if (!cli_rename(targetcli1, targetpath1, targetpath2)) {
1853
 
                int eno = smbc_errno(ocontext, targetcli1);
1854
 
 
1855
 
                if (eno != EEXIST ||
1856
 
                    !cli_unlink(targetcli1, targetpath2) ||
1857
 
                    !cli_rename(targetcli1, targetpath1, targetpath2)) {
1858
 
 
1859
 
                        errno = eno;
1860
 
                        return -1;
1861
 
 
1862
 
                }
1863
 
        }
1864
 
 
1865
 
        return 0; /* Success */
1866
 
 
1867
 
}
1868
 
 
1869
 
/*
1870
 
 * A routine to lseek() a file
1871
 
 */
1872
 
 
1873
 
static off_t
1874
 
smbc_lseek_ctx(SMBCCTX *context,
1875
 
               SMBCFILE *file,
1876
 
               off_t offset,
1877
 
               int whence)
1878
 
{
1879
 
        SMB_OFF_T size;
1880
 
        fstring server, share, user, password;
1881
 
        pstring path, targetpath;
1882
 
        struct cli_state *targetcli;
1883
 
 
1884
 
        if (!context || !context->internal ||
1885
 
            !context->internal->_initialized) {
1886
 
 
1887
 
                errno = EINVAL;
1888
 
                return -1;
1889
 
                
1890
 
        }
1891
 
 
1892
 
        if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
1893
 
 
1894
 
                errno = EBADF;
1895
 
                return -1;
1896
 
 
1897
 
        }
1898
 
 
1899
 
        if (!file->file) {
1900
 
 
1901
 
                errno = EINVAL;
1902
 
                return -1;      /* Can't lseek a dir ... */
1903
 
 
1904
 
        }
1905
 
 
1906
 
        switch (whence) {
1907
 
        case SEEK_SET:
1908
 
                file->offset = offset;
1909
 
                break;
1910
 
 
1911
 
        case SEEK_CUR:
1912
 
                file->offset += offset;
1913
 
                break;
1914
 
 
1915
 
        case SEEK_END:
1916
 
                /*d_printf(">>>lseek: parsing %s\n", file->fname);*/
1917
 
                if (smbc_parse_path(context, file->fname,
1918
 
                                    NULL, 0,
1919
 
                                    server, sizeof(server),
1920
 
                                    share, sizeof(share),
1921
 
                                    path, sizeof(path),
1922
 
                                    user, sizeof(user),
1923
 
                                    password, sizeof(password),
1924
 
                                    NULL, 0)) {
1925
 
                        
1926
 
                                        errno = EINVAL;
1927
 
                                        return -1;
1928
 
                        }
1929
 
                
1930
 
                /*d_printf(">>>lseek: resolving %s\n", path);*/
1931
 
                if (!cli_resolve_path("", file->srv->cli, path,
1932
 
                                      &targetcli, targetpath))
1933
 
                {
1934
 
                        d_printf("Could not resolve %s\n", path);
1935
 
                        return -1;
1936
 
                }
1937
 
                /*d_printf(">>>lseek: resolved path as %s\n", targetpath);*/
1938
 
                
1939
 
                if (!cli_qfileinfo(targetcli, file->cli_fd, NULL,
1940
 
                                   &size, NULL, NULL, NULL, NULL, NULL)) 
1941
 
                {
1942
 
                    SMB_OFF_T b_size = size;
1943
 
                        if (!cli_getattrE(targetcli, file->cli_fd,
1944
 
                                          NULL, &b_size, NULL, NULL, NULL)) 
1945
 
                    {
1946
 
                        errno = EINVAL;
1947
 
                        return -1;
1948
 
                    } else
1949
 
                        size = b_size;
1950
 
                }
1951
 
                file->offset = size + offset;
1952
 
                break;
1953
 
 
1954
 
        default:
1955
 
                errno = EINVAL;
1956
 
                break;
1957
 
 
1958
 
        }
1959
 
 
1960
 
        return file->offset;
1961
 
 
1962
 
}
1963
 
 
1964
 
/* 
1965
 
 * Generate an inode number from file name for those things that need it
1966
 
 */
1967
 
 
1968
 
static ino_t
1969
 
smbc_inode(SMBCCTX *context,
1970
 
           const char *name)
1971
 
{
1972
 
 
1973
 
        if (!context || !context->internal ||
1974
 
            !context->internal->_initialized) {
1975
 
 
1976
 
                errno = EINVAL;
1977
 
                return -1;
1978
 
 
1979
 
        }
1980
 
 
1981
 
        if (!*name) return 2; /* FIXME, why 2 ??? */
1982
 
        return (ino_t)str_checksum(name);
1983
 
 
1984
 
}
1985
 
 
1986
 
/*
1987
 
 * Routine to put basic stat info into a stat structure ... Used by stat and
1988
 
 * fstat below.
1989
 
 */
1990
 
 
1991
 
static int
1992
 
smbc_setup_stat(SMBCCTX *context,
1993
 
                struct stat *st,
1994
 
                char *fname,
1995
 
                SMB_OFF_T size,
1996
 
                int mode)
1997
 
{
1998
 
        
1999
 
        st->st_mode = 0;
2000
 
 
2001
 
        if (IS_DOS_DIR(mode)) {
2002
 
                st->st_mode = SMBC_DIR_MODE;
2003
 
        } else {
2004
 
                st->st_mode = SMBC_FILE_MODE;
2005
 
        }
2006
 
 
2007
 
        if (IS_DOS_ARCHIVE(mode)) st->st_mode |= S_IXUSR;
2008
 
        if (IS_DOS_SYSTEM(mode)) st->st_mode |= S_IXGRP;
2009
 
        if (IS_DOS_HIDDEN(mode)) st->st_mode |= S_IXOTH;
2010
 
        if (!IS_DOS_READONLY(mode)) st->st_mode |= S_IWUSR;
2011
 
 
2012
 
        st->st_size = size;
2013
 
#ifdef HAVE_STAT_ST_BLKSIZE
2014
 
        st->st_blksize = 512;
2015
 
#endif
2016
 
#ifdef HAVE_STAT_ST_BLOCKS
2017
 
        st->st_blocks = (size+511)/512;
2018
 
#endif
2019
 
        st->st_uid = getuid();
2020
 
        st->st_gid = getgid();
2021
 
 
2022
 
        if (IS_DOS_DIR(mode)) {
2023
 
                st->st_nlink = 2;
2024
 
        } else {
2025
 
                st->st_nlink = 1;
2026
 
        }
2027
 
 
2028
 
        if (st->st_ino == 0) {
2029
 
                st->st_ino = smbc_inode(context, fname);
2030
 
        }
2031
 
        
2032
 
        return True;  /* FIXME: Is this needed ? */
2033
 
 
2034
 
}
2035
 
 
2036
 
/*
2037
 
 * Routine to stat a file given a name
2038
 
 */
2039
 
 
2040
 
static int
2041
 
smbc_stat_ctx(SMBCCTX *context,
2042
 
              const char *fname,
2043
 
              struct stat *st)
2044
 
{
2045
 
        SMBCSRV *srv;
2046
 
        fstring server;
2047
 
        fstring share;
2048
 
        fstring user;
2049
 
        fstring password;
2050
 
        fstring workgroup;
2051
 
        pstring path;
2052
 
        time_t m_time = 0;
2053
 
        time_t a_time = 0;
2054
 
        time_t c_time = 0;
2055
 
        SMB_OFF_T size = 0;
2056
 
        uint16 mode = 0;
2057
 
        SMB_INO_T ino = 0;
2058
 
 
2059
 
        if (!context || !context->internal ||
2060
 
            !context->internal->_initialized) {
2061
 
 
2062
 
                errno = EINVAL;  /* Best I can think of ... */
2063
 
                return -1;
2064
 
    
2065
 
        }
2066
 
 
2067
 
        if (!fname) {
2068
 
 
2069
 
                errno = EINVAL;
2070
 
                return -1;
2071
 
 
2072
 
        }
2073
 
  
2074
 
        DEBUG(4, ("smbc_stat(%s)\n", fname));
2075
 
 
2076
 
        if (smbc_parse_path(context, fname,
2077
 
                            workgroup, sizeof(workgroup),
2078
 
                            server, sizeof(server),
2079
 
                            share, sizeof(share),
2080
 
                            path, sizeof(path),
2081
 
                            user, sizeof(user),
2082
 
                            password, sizeof(password),
2083
 
                            NULL, 0)) {
2084
 
                errno = EINVAL;
2085
 
                return -1;
2086
 
        }
2087
 
 
2088
 
        if (user[0] == (char)0) fstrcpy(user, context->user);
2089
 
 
2090
 
        srv = smbc_server(context, True,
2091
 
                          server, share, workgroup, user, password);
2092
 
 
2093
 
        if (!srv) {
2094
 
                return -1;  /* errno set by smbc_server */
2095
 
        }
2096
 
 
2097
 
        if (!smbc_getatr(context, srv, path, &mode, &size, 
2098
 
                         &c_time, &a_time, &m_time, &ino)) {
2099
 
 
2100
 
                errno = smbc_errno(context, srv->cli);
2101
 
                return -1;
2102
 
                
2103
 
        }
2104
 
 
2105
 
        st->st_ino = ino;
2106
 
 
2107
 
        smbc_setup_stat(context, st, path, size, mode);
2108
 
 
2109
 
        st->st_atime = a_time;
2110
 
        st->st_ctime = c_time;
2111
 
        st->st_mtime = m_time;
2112
 
        st->st_dev   = srv->dev;
2113
 
 
2114
 
        return 0;
2115
 
 
2116
 
}
2117
 
 
2118
 
/*
2119
 
 * Routine to stat a file given an fd
2120
 
 */
2121
 
 
2122
 
static int
2123
 
smbc_fstat_ctx(SMBCCTX *context,
2124
 
               SMBCFILE *file,
2125
 
               struct stat *st)
2126
 
{
2127
 
        time_t c_time;
2128
 
        time_t a_time;
2129
 
        time_t m_time;
2130
 
        SMB_OFF_T size;
2131
 
        uint16 mode;
2132
 
        fstring server;
2133
 
        fstring share;
2134
 
        fstring user;
2135
 
        fstring password;
2136
 
        pstring path;
2137
 
        pstring targetpath;
2138
 
        struct cli_state *targetcli;
2139
 
        SMB_INO_T ino = 0;
2140
 
 
2141
 
        if (!context || !context->internal ||
2142
 
            !context->internal->_initialized) {
2143
 
 
2144
 
                errno = EINVAL;
2145
 
                return -1;
2146
 
 
2147
 
        }
2148
 
 
2149
 
        if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
2150
 
 
2151
 
                errno = EBADF;
2152
 
                return -1;
2153
 
 
2154
 
        }
2155
 
 
2156
 
        if (!file->file) {
2157
 
 
2158
 
                return context->fstatdir(context, file, st);
2159
 
 
2160
 
        }
2161
 
 
2162
 
        /*d_printf(">>>fstat: parsing %s\n", file->fname);*/
2163
 
        if (smbc_parse_path(context, file->fname,
2164
 
                            NULL, 0,
2165
 
                            server, sizeof(server),
2166
 
                            share, sizeof(share),
2167
 
                            path, sizeof(path),
2168
 
                            user, sizeof(user),
2169
 
                            password, sizeof(password),
2170
 
                            NULL, 0)) {
2171
 
                errno = EINVAL;
2172
 
                return -1;
2173
 
        }
2174
 
        
2175
 
        /*d_printf(">>>fstat: resolving %s\n", path);*/
2176
 
        if (!cli_resolve_path("", file->srv->cli, path,
2177
 
                              &targetcli, targetpath))
2178
 
        {
2179
 
                d_printf("Could not resolve %s\n", path);
2180
 
                return -1;
2181
 
        }
2182
 
        /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/
2183
 
 
2184
 
        if (!cli_qfileinfo(targetcli, file->cli_fd, &mode, &size,
2185
 
                           &c_time, &a_time, &m_time, NULL, &ino)) {
2186
 
            if (!cli_getattrE(targetcli, file->cli_fd, &mode, &size,
2187
 
                              &c_time, &a_time, &m_time)) {
2188
 
 
2189
 
                errno = EINVAL;
2190
 
                return -1;
2191
 
            }
2192
 
        }
2193
 
 
2194
 
        st->st_ino = ino;
2195
 
 
2196
 
        smbc_setup_stat(context, st, file->fname, size, mode);
2197
 
 
2198
 
        st->st_atime = a_time;
2199
 
        st->st_ctime = c_time;
2200
 
        st->st_mtime = m_time;
2201
 
        st->st_dev = file->srv->dev;
2202
 
 
2203
 
        return 0;
2204
 
 
2205
 
}
2206
 
 
2207
 
/*
2208
 
 * Routine to open a directory
2209
 
 * We accept the URL syntax explained in smbc_parse_path(), above.
2210
 
 */
2211
 
 
2212
 
static void
2213
 
smbc_remove_dir(SMBCFILE *dir)
2214
 
{
2215
 
        struct smbc_dir_list *d,*f;
2216
 
 
2217
 
        d = dir->dir_list;
2218
 
        while (d) {
2219
 
 
2220
 
                f = d; d = d->next;
2221
 
 
2222
 
                SAFE_FREE(f->dirent);
2223
 
                SAFE_FREE(f);
2224
 
 
2225
 
        }
2226
 
 
2227
 
        dir->dir_list = dir->dir_end = dir->dir_next = NULL;
2228
 
 
2229
 
}
2230
 
 
2231
 
static int
2232
 
add_dirent(SMBCFILE *dir,
2233
 
           const char *name,
2234
 
           const char *comment,
2235
 
           uint32 type)
2236
 
{
2237
 
        struct smbc_dirent *dirent;
2238
 
        int size;
2239
 
        int name_length = (name == NULL ? 0 : strlen(name));
2240
 
        int comment_len = (comment == NULL ? 0 : strlen(comment));
2241
 
 
2242
 
        /*
2243
 
         * Allocate space for the dirent, which must be increased by the 
2244
 
         * size of the name and the comment and 1 each for the null terminator.
2245
 
         */
2246
 
 
2247
 
        size = sizeof(struct smbc_dirent) + name_length + comment_len + 2;
2248
 
    
2249
 
        dirent = SMB_MALLOC(size);
2250
 
 
2251
 
        if (!dirent) {
2252
 
 
2253
 
                dir->dir_error = ENOMEM;
2254
 
                return -1;
2255
 
 
2256
 
        }
2257
 
 
2258
 
        ZERO_STRUCTP(dirent);
2259
 
 
2260
 
        if (dir->dir_list == NULL) {
2261
 
 
2262
 
                dir->dir_list = SMB_MALLOC_P(struct smbc_dir_list);
2263
 
                if (!dir->dir_list) {
2264
 
 
2265
 
                        SAFE_FREE(dirent);
2266
 
                        dir->dir_error = ENOMEM;
2267
 
                        return -1;
2268
 
 
2269
 
                }
2270
 
                ZERO_STRUCTP(dir->dir_list);
2271
 
 
2272
 
                dir->dir_end = dir->dir_next = dir->dir_list;
2273
 
        }
2274
 
        else {
2275
 
 
2276
 
                dir->dir_end->next = SMB_MALLOC_P(struct smbc_dir_list);
2277
 
                
2278
 
                if (!dir->dir_end->next) {
2279
 
                        
2280
 
                        SAFE_FREE(dirent);
2281
 
                        dir->dir_error = ENOMEM;
2282
 
                        return -1;
2283
 
 
2284
 
                }
2285
 
                ZERO_STRUCTP(dir->dir_end->next);
2286
 
 
2287
 
                dir->dir_end = dir->dir_end->next;
2288
 
        }
2289
 
 
2290
 
        dir->dir_end->next = NULL;
2291
 
        dir->dir_end->dirent = dirent;
2292
 
        
2293
 
        dirent->smbc_type = type;
2294
 
        dirent->namelen = name_length;
2295
 
        dirent->commentlen = comment_len;
2296
 
        dirent->dirlen = size;
2297
 
  
2298
 
        /*
2299
 
         * dirent->namelen + 1 includes the null (no null termination needed)
2300
 
         * Ditto for dirent->commentlen.
2301
 
         * The space for the two null bytes was allocated.
2302
 
         */
2303
 
        strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
2304
 
        dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
2305
 
        strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
2306
 
        
2307
 
        return 0;
2308
 
 
2309
 
}
2310
 
 
2311
 
static void
2312
 
list_unique_wg_fn(const char *name,
2313
 
                  uint32 type,
2314
 
                  const char *comment,
2315
 
                  void *state)
2316
 
{
2317
 
        SMBCFILE *dir = (SMBCFILE *)state;
2318
 
        struct smbc_dir_list *dir_list;
2319
 
        struct smbc_dirent *dirent;
2320
 
        int dirent_type;
2321
 
        int do_remove = 0;
2322
 
 
2323
 
        dirent_type = dir->dir_type;
2324
 
 
2325
 
        if (add_dirent(dir, name, comment, dirent_type) < 0) {
2326
 
 
2327
 
                /* An error occurred, what do we do? */
2328
 
                /* FIXME: Add some code here */
2329
 
        }
2330
 
 
2331
 
        /* Point to the one just added */
2332
 
        dirent = dir->dir_end->dirent;
2333
 
 
2334
 
        /* See if this was a duplicate */
2335
 
        for (dir_list = dir->dir_list;
2336
 
             dir_list != dir->dir_end;
2337
 
             dir_list = dir_list->next) {
2338
 
                if (! do_remove &&
2339
 
                    strcmp(dir_list->dirent->name, dirent->name) == 0) {
2340
 
                        /* Duplicate.  End end of list need to be removed. */
2341
 
                        do_remove = 1;
2342
 
                }
2343
 
 
2344
 
                if (do_remove && dir_list->next == dir->dir_end) {
2345
 
                        /* Found the end of the list.  Remove it. */
2346
 
                        dir->dir_end = dir_list;
2347
 
                        free(dir_list->next);
2348
 
                        free(dirent);
2349
 
                        dir_list->next = NULL;
2350
 
                        break;
2351
 
                }
2352
 
        }
2353
 
}
2354
 
 
2355
 
static void
2356
 
list_fn(const char *name,
2357
 
        uint32 type,
2358
 
        const char *comment,
2359
 
        void *state)
2360
 
{
2361
 
        SMBCFILE *dir = (SMBCFILE *)state;
2362
 
        int dirent_type;
2363
 
 
2364
 
        /*
2365
 
         * We need to process the type a little ...
2366
 
         *
2367
 
         * Disk share     = 0x00000000
2368
 
         * Print share    = 0x00000001
2369
 
         * Comms share    = 0x00000002 (obsolete?)
2370
 
         * IPC$ share     = 0x00000003 
2371
 
         *
2372
 
         * administrative shares:
2373
 
         * ADMIN$, IPC$, C$, D$, E$ ...  are type |= 0x80000000
2374
 
         */
2375
 
        
2376
 
        if (dir->dir_type == SMBC_FILE_SHARE) {
2377
 
                
2378
 
                switch (type) {
2379
 
                case 0 | 0x80000000:
2380
 
                case 0:
2381
 
                        dirent_type = SMBC_FILE_SHARE;
2382
 
                        break;
2383
 
 
2384
 
                case 1:
2385
 
                        dirent_type = SMBC_PRINTER_SHARE;
2386
 
                        break;
2387
 
 
2388
 
                case 2:
2389
 
                        dirent_type = SMBC_COMMS_SHARE;
2390
 
                        break;
2391
 
 
2392
 
                case 3 | 0x80000000:
2393
 
                case 3:
2394
 
                        dirent_type = SMBC_IPC_SHARE;
2395
 
                        break;
2396
 
 
2397
 
                default:
2398
 
                        dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */
2399
 
                        break;
2400
 
                }
2401
 
        }
2402
 
        else {
2403
 
                dirent_type = dir->dir_type;
2404
 
        }
2405
 
 
2406
 
        if (add_dirent(dir, name, comment, dirent_type) < 0) {
2407
 
 
2408
 
                /* An error occurred, what do we do? */
2409
 
                /* FIXME: Add some code here */
2410
 
 
2411
 
        }
2412
 
}
2413
 
 
2414
 
static void
2415
 
dir_list_fn(const char *mnt,
2416
 
            file_info *finfo,
2417
 
            const char *mask,
2418
 
            void *state)
2419
 
{
2420
 
 
2421
 
        if (add_dirent((SMBCFILE *)state, finfo->name, "", 
2422
 
                       (finfo->mode&aDIR?SMBC_DIR:SMBC_FILE)) < 0) {
2423
 
 
2424
 
                /* Handle an error ... */
2425
 
 
2426
 
                /* FIXME: Add some code ... */
2427
 
 
2428
 
        } 
2429
 
 
2430
 
}
2431
 
 
2432
 
static int
2433
 
net_share_enum_rpc(struct cli_state *cli,
2434
 
                   void (*fn)(const char *name,
2435
 
                              uint32 type,
2436
 
                              const char *comment,
2437
 
                              void *state),
2438
 
                   void *state)
2439
 
{
2440
 
        int i;
2441
 
        WERROR result;
2442
 
        ENUM_HND enum_hnd;
2443
 
        uint32 info_level = 1;
2444
 
        uint32 preferred_len = 0xffffffff;
2445
 
        uint32 type;
2446
 
        SRV_SHARE_INFO_CTR ctr;
2447
 
        fstring name = "";
2448
 
        fstring comment = "";
2449
 
        void *mem_ctx;
2450
 
        struct rpc_pipe_client *pipe_hnd;
2451
 
        NTSTATUS nt_status;
2452
 
 
2453
 
        /* Open the server service pipe */
2454
 
        pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SRVSVC, &nt_status);
2455
 
        if (!pipe_hnd) {
2456
 
                DEBUG(1, ("net_share_enum_rpc pipe open fail!\n"));
2457
 
                return -1;
2458
 
        }
2459
 
 
2460
 
        /* Allocate a context for parsing and for the entries in "ctr" */
2461
 
        mem_ctx = talloc_init("libsmbclient: net_share_enum_rpc");
2462
 
        if (mem_ctx == NULL) {
2463
 
                DEBUG(0, ("out of memory for net_share_enum_rpc!\n"));
2464
 
                cli_rpc_pipe_close(pipe_hnd);
2465
 
                return -1; 
2466
 
        }
2467
 
 
2468
 
        /* Issue the NetShareEnum RPC call and retrieve the response */
2469
 
        init_enum_hnd(&enum_hnd, 0);
2470
 
        result = rpccli_srvsvc_net_share_enum(pipe_hnd,
2471
 
                                              mem_ctx,
2472
 
                                              info_level,
2473
 
                                              &ctr,
2474
 
                                              preferred_len,
2475
 
                                              &enum_hnd);
2476
 
 
2477
 
        /* Was it successful? */
2478
 
        if (!W_ERROR_IS_OK(result) || ctr.num_entries == 0) {
2479
 
                /*  Nope.  Go clean up. */
2480
 
                goto done;
2481
 
        }
2482
 
 
2483
 
        /* For each returned entry... */
2484
 
        for (i = 0; i < ctr.num_entries; i++) {
2485
 
 
2486
 
                /* pull out the share name */
2487
 
                rpcstr_pull_unistr2_fstring(
2488
 
                        name, &ctr.share.info1[i].info_1_str.uni_netname);
2489
 
 
2490
 
                /* pull out the share's comment */
2491
 
                rpcstr_pull_unistr2_fstring(
2492
 
                        comment, &ctr.share.info1[i].info_1_str.uni_remark);
2493
 
 
2494
 
                /* Get the type value */
2495
 
                type = ctr.share.info1[i].info_1.type;
2496
 
 
2497
 
                /* Add this share to the list */
2498
 
                (*fn)(name, type, comment, state);
2499
 
        }
2500
 
 
2501
 
done:
2502
 
        /* Close the server service pipe */
2503
 
        cli_rpc_pipe_close(pipe_hnd);
2504
 
 
2505
 
        /* Free all memory which was allocated for this request */
2506
 
        TALLOC_FREE(mem_ctx);
2507
 
 
2508
 
        /* Tell 'em if it worked */
2509
 
        return W_ERROR_IS_OK(result) ? 0 : -1;
2510
 
}
2511
 
 
2512
 
 
2513
 
 
2514
 
static SMBCFILE *
2515
 
smbc_opendir_ctx(SMBCCTX *context,
2516
 
                 const char *fname)
2517
 
{
2518
 
        fstring server, share, user, password, options;
2519
 
        pstring workgroup;
2520
 
        pstring path;
2521
 
        uint16 mode;
2522
 
        char *p;
2523
 
        SMBCSRV *srv  = NULL;
2524
 
        SMBCFILE *dir = NULL;
2525
 
        struct in_addr rem_ip;
2526
 
 
2527
 
        if (!context || !context->internal ||
2528
 
            !context->internal->_initialized) {
2529
 
                DEBUG(4, ("no valid context\n"));
2530
 
                errno = EINVAL + 8192;
2531
 
                return NULL;
2532
 
 
2533
 
        }
2534
 
 
2535
 
        if (!fname) {
2536
 
                DEBUG(4, ("no valid fname\n"));
2537
 
                errno = EINVAL + 8193;
2538
 
                return NULL;
2539
 
        }
2540
 
 
2541
 
        if (smbc_parse_path(context, fname,
2542
 
                            workgroup, sizeof(workgroup),
2543
 
                            server, sizeof(server),
2544
 
                            share, sizeof(share),
2545
 
                            path, sizeof(path),
2546
 
                            user, sizeof(user),
2547
 
                            password, sizeof(password),
2548
 
                            options, sizeof(options))) {
2549
 
                DEBUG(4, ("no valid path\n"));
2550
 
                errno = EINVAL + 8194;
2551
 
                return NULL;
2552
 
        }
2553
 
 
2554
 
        DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' "
2555
 
                  "path='%s' options='%s'\n",
2556
 
                  fname, server, share, path, options));
2557
 
 
2558
 
        /* Ensure the options are valid */
2559
 
        if (smbc_check_options(server, share, path, options)) {
2560
 
                DEBUG(4, ("unacceptable options (%s)\n", options));
2561
 
                errno = EINVAL + 8195;
2562
 
                return NULL;
2563
 
        }
2564
 
 
2565
 
        if (user[0] == (char)0) fstrcpy(user, context->user);
2566
 
 
2567
 
        dir = SMB_MALLOC_P(SMBCFILE);
2568
 
 
2569
 
        if (!dir) {
2570
 
 
2571
 
                errno = ENOMEM;
2572
 
                return NULL;
2573
 
 
2574
 
        }
2575
 
 
2576
 
        ZERO_STRUCTP(dir);
2577
 
 
2578
 
        dir->cli_fd   = 0;
2579
 
        dir->fname    = SMB_STRDUP(fname);
2580
 
        dir->srv      = NULL;
2581
 
        dir->offset   = 0;
2582
 
        dir->file     = False;
2583
 
        dir->dir_list = dir->dir_next = dir->dir_end = NULL;
2584
 
 
2585
 
        if (server[0] == (char)0) {
2586
 
 
2587
 
                int i;
2588
 
                int count;
2589
 
                int max_lmb_count;
2590
 
                struct ip_service *ip_list;
2591
 
                struct ip_service server_addr;
2592
 
                struct user_auth_info u_info;
2593
 
                struct cli_state *cli;
2594
 
 
2595
 
                if (share[0] != (char)0 || path[0] != (char)0) {
2596
 
 
2597
 
                        errno = EINVAL + 8196;
2598
 
                        if (dir) {
2599
 
                                SAFE_FREE(dir->fname);
2600
 
                                SAFE_FREE(dir);
2601
 
                        }
2602
 
                        return NULL;
2603
 
                }
2604
 
 
2605
 
                /* Determine how many local master browsers to query */
2606
 
                max_lmb_count = (context->options.browse_max_lmb_count == 0
2607
 
                                 ? INT_MAX
2608
 
                                 : context->options.browse_max_lmb_count);
2609
 
 
2610
 
                pstrcpy(u_info.username, user);
2611
 
                pstrcpy(u_info.password, password);
2612
 
 
2613
 
                /*
2614
 
                 * We have server and share and path empty but options
2615
 
                 * requesting that we scan all master browsers for their list
2616
 
                 * of workgroups/domains.  This implies that we must first try
2617
 
                 * broadcast queries to find all master browsers, and if that
2618
 
                 * doesn't work, then try our other methods which return only
2619
 
                 * a single master browser.
2620
 
                 */
2621
 
 
2622
 
                ip_list = NULL;
2623
 
                if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) {
2624
 
 
2625
 
                        SAFE_FREE(ip_list);
2626
 
 
2627
 
                        if (!find_master_ip(workgroup, &server_addr.ip)) {
2628
 
 
2629
 
                                if (dir) {
2630
 
                                        SAFE_FREE(dir->fname);
2631
 
                                        SAFE_FREE(dir);
2632
 
                                }
2633
 
                                errno = ENOENT;
2634
 
                                return NULL;
2635
 
                        }
2636
 
 
2637
 
                        ip_list = &server_addr;
2638
 
                        count = 1;
2639
 
                }
2640
 
 
2641
 
                for (i = 0; i < count && i < max_lmb_count; i++) {
2642
 
                        DEBUG(99, ("Found master browser %d of %d: %s\n",
2643
 
                                   i+1, MAX(count, max_lmb_count),
2644
 
                                   inet_ntoa(ip_list[i].ip)));
2645
 
                        
2646
 
                        cli = get_ipc_connect_master_ip(&ip_list[i],
2647
 
                                                        workgroup, &u_info);
2648
 
                        /* cli == NULL is the master browser refused to talk or 
2649
 
                           could not be found */
2650
 
                        if ( !cli )
2651
 
                                continue;
2652
 
 
2653
 
                        fstrcpy(server, cli->desthost);
2654
 
                        cli_shutdown(cli);
2655
 
 
2656
 
                        DEBUG(4, ("using workgroup %s %s\n",
2657
 
                                  workgroup, server));
2658
 
 
2659
 
                        /*
2660
 
                         * For each returned master browser IP address, get a
2661
 
                         * connection to IPC$ on the server if we do not
2662
 
                         * already have one, and determine the
2663
 
                         * workgroups/domains that it knows about.
2664
 
                         */
2665
 
                
2666
 
                        srv = smbc_server(context, True, server, "IPC$",
2667
 
                                          workgroup, user, password);
2668
 
                        if (!srv) {
2669
 
                                continue;
2670
 
                        }
2671
 
                
2672
 
                        dir->srv = srv;
2673
 
                        dir->dir_type = SMBC_WORKGROUP;
2674
 
 
2675
 
                        /* Now, list the stuff ... */
2676
 
                        
2677
 
                        if (!cli_NetServerEnum(srv->cli,
2678
 
                                               workgroup,
2679
 
                                               SV_TYPE_DOMAIN_ENUM,
2680
 
                                               list_unique_wg_fn,
2681
 
                                               (void *)dir)) {
2682
 
                                continue;
2683
 
                        }
2684
 
                }
2685
 
 
2686
 
                SAFE_FREE(ip_list);
2687
 
        } else { 
2688
 
                /*
2689
 
                 * Server not an empty string ... Check the rest and see what
2690
 
                 * gives
2691
 
                 */
2692
 
                if (*share == '\0') {
2693
 
                        if (*path != '\0') {
2694
 
 
2695
 
                                /* Should not have empty share with path */
2696
 
                                errno = EINVAL + 8197;
2697
 
                                if (dir) {
2698
 
                                        SAFE_FREE(dir->fname);
2699
 
                                        SAFE_FREE(dir);
2700
 
                                }
2701
 
                                return NULL;
2702
 
        
2703
 
                        }
2704
 
 
2705
 
                        /*
2706
 
                         * We don't know if <server> is really a server name
2707
 
                         * or is a workgroup/domain name.  If we already have
2708
 
                         * a server structure for it, we'll use it.
2709
 
                         * Otherwise, check to see if <server><1D>,
2710
 
                         * <server><1B>, or <server><20> translates.  We check
2711
 
                         * to see if <server> is an IP address first.
2712
 
                         */
2713
 
 
2714
 
                        /*
2715
 
                         * See if we have an existing server.  Do not
2716
 
                         * establish a connection if one does not already
2717
 
                         * exist.
2718
 
                         */
2719
 
                        srv = smbc_server(context, False, server, "IPC$",
2720
 
                                          workgroup, user, password);
2721
 
 
2722
 
                        /*
2723
 
                         * If no existing server and not an IP addr, look for
2724
 
                         * LMB or DMB
2725
 
                         */
2726
 
                        if (!srv &&
2727
 
                            !is_ipaddress(server) &&
2728
 
                            (resolve_name(server, &rem_ip, 0x1d) ||   /* LMB */
2729
 
                             resolve_name(server, &rem_ip, 0x1b) )) { /* DMB */
2730
 
 
2731
 
                                fstring buserver;
2732
 
 
2733
 
                                dir->dir_type = SMBC_SERVER;
2734
 
 
2735
 
                                /*
2736
 
                                 * Get the backup list ...
2737
 
                                 */
2738
 
                                if (!name_status_find(server, 0, 0,
2739
 
                                                      rem_ip, buserver)) {
2740
 
 
2741
 
                                        DEBUG(0, ("Could not get name of "
2742
 
                                                  "local/domain master browser "
2743
 
                                                  "for server %s\n", server));
2744
 
                                        if (dir) {
2745
 
                                                SAFE_FREE(dir->fname);
2746
 
                                                SAFE_FREE(dir);
2747
 
                                        }
2748
 
                                        errno = EPERM;
2749
 
                                        return NULL;
2750
 
 
2751
 
                                }
2752
 
 
2753
 
                                /*
2754
 
                                 * Get a connection to IPC$ on the server if
2755
 
                                 * we do not already have one
2756
 
                                 */
2757
 
                                srv = smbc_server(context, True,
2758
 
                                                  buserver, "IPC$",
2759
 
                                                  workgroup, user, password);
2760
 
                                if (!srv) {
2761
 
                                        DEBUG(0, ("got no contact to IPC$\n"));
2762
 
                                        if (dir) {
2763
 
                                                SAFE_FREE(dir->fname);
2764
 
                                                SAFE_FREE(dir);
2765
 
                                        }
2766
 
                                        return NULL;
2767
 
 
2768
 
                                }
2769
 
 
2770
 
                                dir->srv = srv;
2771
 
 
2772
 
                                /* Now, list the servers ... */
2773
 
                                if (!cli_NetServerEnum(srv->cli, server,
2774
 
                                                       0x0000FFFE, list_fn,
2775
 
                                                       (void *)dir)) {
2776
 
 
2777
 
                                        if (dir) {
2778
 
                                                SAFE_FREE(dir->fname);
2779
 
                                                SAFE_FREE(dir);
2780
 
                                        }
2781
 
                                        return NULL;
2782
 
                                }
2783
 
                        } else if (srv ||
2784
 
                                   (resolve_name(server, &rem_ip, 0x20))) {
2785
 
                                
2786
 
                                /* If we hadn't found the server, get one now */
2787
 
                                if (!srv) {
2788
 
                                        srv = smbc_server(context, True,
2789
 
                                                          server, "IPC$",
2790
 
                                                          workgroup,
2791
 
                                                          user, password);
2792
 
                                }
2793
 
 
2794
 
                                if (!srv) {
2795
 
                                        if (dir) {
2796
 
                                                SAFE_FREE(dir->fname);
2797
 
                                                SAFE_FREE(dir);
2798
 
                                        }
2799
 
                                        return NULL;
2800
 
 
2801
 
                                }
2802
 
 
2803
 
                                dir->dir_type = SMBC_FILE_SHARE;
2804
 
                                dir->srv = srv;
2805
 
 
2806
 
                                /* List the shares ... */
2807
 
 
2808
 
                                if (net_share_enum_rpc(
2809
 
                                            srv->cli,
2810
 
                                            list_fn,
2811
 
                                            (void *) dir) < 0 &&
2812
 
                                    cli_RNetShareEnum(
2813
 
                                            srv->cli,
2814
 
                                            list_fn, 
2815
 
                                            (void *)dir) < 0) {
2816
 
                                                
2817
 
                                        errno = cli_errno(srv->cli);
2818
 
                                        if (dir) {
2819
 
                                                SAFE_FREE(dir->fname);
2820
 
                                                SAFE_FREE(dir);
2821
 
                                        }
2822
 
                                        return NULL;
2823
 
 
2824
 
                                }
2825
 
                        } else {
2826
 
                                /* Neither the workgroup nor server exists */
2827
 
                                errno = ECONNREFUSED;   
2828
 
                                if (dir) {
2829
 
                                        SAFE_FREE(dir->fname);
2830
 
                                        SAFE_FREE(dir);
2831
 
                                }
2832
 
                                return NULL;
2833
 
                        }
2834
 
 
2835
 
                }
2836
 
                else {
2837
 
                        /*
2838
 
                         * The server and share are specified ... work from
2839
 
                         * there ...
2840
 
                         */
2841
 
                        pstring targetpath;
2842
 
                        struct cli_state *targetcli;
2843
 
 
2844
 
                        /* We connect to the server and list the directory */
2845
 
                        dir->dir_type = SMBC_FILE_SHARE;
2846
 
 
2847
 
                        srv = smbc_server(context, True, server, share,
2848
 
                                          workgroup, user, password);
2849
 
 
2850
 
                        if (!srv) {
2851
 
 
2852
 
                                if (dir) {
2853
 
                                        SAFE_FREE(dir->fname);
2854
 
                                        SAFE_FREE(dir);
2855
 
                                }
2856
 
                                return NULL;
2857
 
 
2858
 
                        }
2859
 
 
2860
 
                        dir->srv = srv;
2861
 
 
2862
 
                        /* Now, list the files ... */
2863
 
 
2864
 
                        p = path + strlen(path);
2865
 
                        pstrcat(path, "\\*");
2866
 
 
2867
 
                        if (!cli_resolve_path("", srv->cli, path,
2868
 
                                              &targetcli, targetpath))
2869
 
                        {
2870
 
                                d_printf("Could not resolve %s\n", path);
2871
 
                                if (dir) {
2872
 
                                        SAFE_FREE(dir->fname);
2873
 
                                        SAFE_FREE(dir);
2874
 
                                }
2875
 
                                return NULL;
2876
 
                        }
2877
 
                        
2878
 
                        if (cli_list(targetcli, targetpath,
2879
 
                                     aDIR | aSYSTEM | aHIDDEN,
2880
 
                                     dir_list_fn, (void *)dir) < 0) {
2881
 
 
2882
 
                                if (dir) {
2883
 
                                        SAFE_FREE(dir->fname);
2884
 
                                        SAFE_FREE(dir);
2885
 
                                }
2886
 
                                errno = smbc_errno(context, targetcli);
2887
 
 
2888
 
                                if (errno == EINVAL) {
2889
 
                                    /*
2890
 
                                     * See if they asked to opendir something
2891
 
                                     * other than a directory.  If so, the
2892
 
                                     * converted error value we got would have
2893
 
                                     * been EINVAL rather than ENOTDIR.
2894
 
                                     */
2895
 
                                    *p = '\0'; /* restore original path */
2896
 
 
2897
 
                                    if (smbc_getatr(context, srv, path,
2898
 
                                                    &mode, NULL,
2899
 
                                                    NULL, NULL, NULL,
2900
 
                                                    NULL) &&
2901
 
                                        ! IS_DOS_DIR(mode)) {
2902
 
 
2903
 
                                        /* It is.  Correct the error value */
2904
 
                                        errno = ENOTDIR;
2905
 
                                    }
2906
 
                                }
2907
 
 
2908
 
                                return NULL;
2909
 
 
2910
 
                        }
2911
 
                }
2912
 
 
2913
 
        }
2914
 
 
2915
 
        DLIST_ADD(context->internal->_files, dir);
2916
 
        return dir;
2917
 
 
2918
 
}
2919
 
 
2920
 
/*
2921
 
 * Routine to close a directory
2922
 
 */
2923
 
 
2924
 
static int
2925
 
smbc_closedir_ctx(SMBCCTX *context,
2926
 
                  SMBCFILE *dir)
2927
 
{
2928
 
 
2929
 
        if (!context || !context->internal ||
2930
 
            !context->internal->_initialized) {
2931
 
 
2932
 
                errno = EINVAL;
2933
 
                return -1;
2934
 
 
2935
 
        }
2936
 
 
2937
 
        if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) {
2938
 
 
2939
 
                errno = EBADF;
2940
 
                return -1;
2941
 
    
2942
 
        }
2943
 
 
2944
 
        smbc_remove_dir(dir); /* Clean it up */
2945
 
 
2946
 
        DLIST_REMOVE(context->internal->_files, dir);
2947
 
 
2948
 
        if (dir) {
2949
 
 
2950
 
                SAFE_FREE(dir->fname);
2951
 
                SAFE_FREE(dir);    /* Free the space too */
2952
 
        }
2953
 
 
2954
 
        return 0;
2955
 
 
2956
 
}
2957
 
 
2958
 
static void
2959
 
smbc_readdir_internal(SMBCCTX * context,
2960
 
                      struct smbc_dirent *dest,
2961
 
                      struct smbc_dirent *src,
2962
 
                      int max_namebuf_len)
2963
 
{
2964
 
        if (context->options.urlencode_readdir_entries) {
2965
 
 
2966
 
                /* url-encode the name.  get back remaining buffer space */
2967
 
                max_namebuf_len =
2968
 
                        smbc_urlencode(dest->name, src->name, max_namebuf_len);
2969
 
 
2970
 
                /* We now know the name length */
2971
 
                dest->namelen = strlen(dest->name);
2972
 
 
2973
 
                /* Save the pointer to the beginning of the comment */
2974
 
                dest->comment = dest->name + dest->namelen + 1;
2975
 
 
2976
 
                /* Copy the comment */
2977
 
                strncpy(dest->comment, src->comment, max_namebuf_len - 1);
2978
 
                dest->comment[max_namebuf_len - 1] = '\0';
2979
 
 
2980
 
                /* Save other fields */
2981
 
                dest->smbc_type = src->smbc_type;
2982
 
                dest->commentlen = strlen(dest->comment);
2983
 
                dest->dirlen = ((dest->comment + dest->commentlen + 1) -
2984
 
                                (char *) dest);
2985
 
        } else {
2986
 
 
2987
 
                /* No encoding.  Just copy the entry as is. */
2988
 
                memcpy(dest, src, src->dirlen);
2989
 
                dest->comment = (char *)(&dest->name + src->namelen + 1);
2990
 
        }
2991
 
        
2992
 
}
2993
 
 
2994
 
/*
2995
 
 * Routine to get a directory entry
2996
 
 */
2997
 
 
2998
 
struct smbc_dirent *
2999
 
smbc_readdir_ctx(SMBCCTX *context,
3000
 
                 SMBCFILE *dir)
3001
 
{
3002
 
        int maxlen;
3003
 
        struct smbc_dirent *dirp, *dirent;
3004
 
 
3005
 
        /* Check that all is ok first ... */
3006
 
 
3007
 
        if (!context || !context->internal ||
3008
 
            !context->internal->_initialized) {
3009
 
 
3010
 
                errno = EINVAL;
3011
 
                DEBUG(0, ("Invalid context in smbc_readdir_ctx()\n"));
3012
 
                return NULL;
3013
 
 
3014
 
        }
3015
 
 
3016
 
        if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) {
3017
 
 
3018
 
                errno = EBADF;
3019
 
                DEBUG(0, ("Invalid dir in smbc_readdir_ctx()\n"));
3020
 
                return NULL;
3021
 
 
3022
 
        }
3023
 
 
3024
 
        if (dir->file != False) { /* FIXME, should be dir, perhaps */
3025
 
 
3026
 
                errno = ENOTDIR;
3027
 
                DEBUG(0, ("Found file vs directory in smbc_readdir_ctx()\n"));
3028
 
                return NULL;
3029
 
 
3030
 
        }
3031
 
 
3032
 
        if (!dir->dir_next) {
3033
 
                return NULL;
3034
 
        }
3035
 
 
3036
 
        dirent = dir->dir_next->dirent;
3037
 
        if (!dirent) {
3038
 
 
3039
 
                errno = ENOENT;
3040
 
                return NULL;
3041
 
 
3042
 
        }
3043
 
 
3044
 
        dirp = (struct smbc_dirent *)context->internal->_dirent;
3045
 
        maxlen = (sizeof(context->internal->_dirent) -
3046
 
                  sizeof(struct smbc_dirent));
3047
 
 
3048
 
        smbc_readdir_internal(context, dirp, dirent, maxlen);
3049
 
 
3050
 
        dir->dir_next = dir->dir_next->next;
3051
 
 
3052
 
        return dirp;
3053
 
}
3054
 
 
3055
 
/*
3056
 
 * Routine to get directory entries
3057
 
 */
3058
 
 
3059
 
static int
3060
 
smbc_getdents_ctx(SMBCCTX *context,
3061
 
                  SMBCFILE *dir,
3062
 
                  struct smbc_dirent *dirp,
3063
 
                  int count)
3064
 
{
3065
 
        int rem = count;
3066
 
        int reqd;
3067
 
        int maxlen;
3068
 
        char *ndir = (char *)dirp;
3069
 
        struct smbc_dir_list *dirlist;
3070
 
 
3071
 
        /* Check that all is ok first ... */
3072
 
 
3073
 
        if (!context || !context->internal ||
3074
 
            !context->internal->_initialized) {
3075
 
 
3076
 
                errno = EINVAL;
3077
 
                return -1;
3078
 
 
3079
 
        }
3080
 
 
3081
 
        if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) {
3082
 
 
3083
 
                errno = EBADF;
3084
 
                return -1;
3085
 
    
3086
 
        }
3087
 
 
3088
 
        if (dir->file != False) { /* FIXME, should be dir, perhaps */
3089
 
 
3090
 
                errno = ENOTDIR;
3091
 
                return -1;
3092
 
 
3093
 
        }
3094
 
 
3095
 
        /* 
3096
 
         * Now, retrieve the number of entries that will fit in what was passed
3097
 
         * We have to figure out if the info is in the list, or we need to 
3098
 
         * send a request to the server to get the info.
3099
 
         */
3100
 
 
3101
 
        while ((dirlist = dir->dir_next)) {
3102
 
                struct smbc_dirent *dirent;
3103
 
 
3104
 
                if (!dirlist->dirent) {
3105
 
 
3106
 
                        errno = ENOENT;  /* Bad error */
3107
 
                        return -1;
3108
 
 
3109
 
                }
3110
 
 
3111
 
                /* Do urlencoding of next entry, if so selected */
3112
 
                dirent = (struct smbc_dirent *)context->internal->_dirent;
3113
 
                maxlen = (sizeof(context->internal->_dirent) -
3114
 
                          sizeof(struct smbc_dirent));
3115
 
                smbc_readdir_internal(context, dirent, dirlist->dirent, maxlen);
3116
 
 
3117
 
                reqd = dirent->dirlen;
3118
 
 
3119
 
                if (rem < reqd) {
3120
 
 
3121
 
                        if (rem < count) { /* We managed to copy something */
3122
 
 
3123
 
                                errno = 0;
3124
 
                                return count - rem;
3125
 
 
3126
 
                        }
3127
 
                        else { /* Nothing copied ... */
3128
 
 
3129
 
                                errno = EINVAL;  /* Not enough space ... */
3130
 
                                return -1;
3131
 
 
3132
 
                        }
3133
 
 
3134
 
                }
3135
 
 
3136
 
                memcpy(ndir, dirent, reqd); /* Copy the data in ... */
3137
 
    
3138
 
                ((struct smbc_dirent *)ndir)->comment = 
3139
 
                        (char *)(&((struct smbc_dirent *)ndir)->name +
3140
 
                                 dirent->namelen +
3141
 
                                 1);
3142
 
 
3143
 
                ndir += reqd;
3144
 
 
3145
 
                rem -= reqd;
3146
 
 
3147
 
                dir->dir_next = dirlist = dirlist -> next;
3148
 
        }
3149
 
 
3150
 
        if (rem == count)
3151
 
                return 0;
3152
 
        else 
3153
 
                return count - rem;
3154
 
 
3155
 
}
3156
 
 
3157
 
/*
3158
 
 * Routine to create a directory ...
3159
 
 */
3160
 
 
3161
 
static int
3162
 
smbc_mkdir_ctx(SMBCCTX *context,
3163
 
               const char *fname,
3164
 
               mode_t mode)
3165
 
{
3166
 
        SMBCSRV *srv;
3167
 
        fstring server;
3168
 
        fstring share;
3169
 
        fstring user;
3170
 
        fstring password;
3171
 
        fstring workgroup;
3172
 
        pstring path, targetpath;
3173
 
        struct cli_state *targetcli;
3174
 
 
3175
 
        if (!context || !context->internal || 
3176
 
            !context->internal->_initialized) {
3177
 
 
3178
 
                errno = EINVAL;
3179
 
                return -1;
3180
 
 
3181
 
        }
3182
 
 
3183
 
        if (!fname) {
3184
 
 
3185
 
                errno = EINVAL;
3186
 
                return -1;
3187
 
 
3188
 
        }
3189
 
  
3190
 
        DEBUG(4, ("smbc_mkdir(%s)\n", fname));
3191
 
 
3192
 
        if (smbc_parse_path(context, fname,
3193
 
                            workgroup, sizeof(workgroup),
3194
 
                            server, sizeof(server),
3195
 
                            share, sizeof(share),
3196
 
                            path, sizeof(path),
3197
 
                            user, sizeof(user),
3198
 
                            password, sizeof(password),
3199
 
                            NULL, 0)) {
3200
 
                errno = EINVAL;
3201
 
                return -1;
3202
 
        }
3203
 
 
3204
 
        if (user[0] == (char)0) fstrcpy(user, context->user);
3205
 
 
3206
 
        srv = smbc_server(context, True,
3207
 
                          server, share, workgroup, user, password);
3208
 
 
3209
 
        if (!srv) {
3210
 
 
3211
 
                return -1;  /* errno set by smbc_server */
3212
 
 
3213
 
        }
3214
 
 
3215
 
        /*d_printf(">>>mkdir: resolving %s\n", path);*/
3216
 
        if (!cli_resolve_path( "", srv->cli, path, &targetcli, targetpath))
3217
 
        {
3218
 
                d_printf("Could not resolve %s\n", path);
3219
 
                return -1;
3220
 
        }
3221
 
        /*d_printf(">>>mkdir: resolved path as %s\n", targetpath);*/
3222
 
 
3223
 
        if (!cli_mkdir(targetcli, targetpath)) {
3224
 
 
3225
 
                errno = smbc_errno(context, targetcli);
3226
 
                return -1;
3227
 
 
3228
 
        } 
3229
 
 
3230
 
        return 0;
3231
 
 
3232
 
}
3233
 
 
3234
 
/*
3235
 
 * Our list function simply checks to see if a directory is not empty
3236
 
 */
3237
 
 
3238
 
static int smbc_rmdir_dirempty = True;
3239
 
 
3240
 
static void
3241
 
rmdir_list_fn(const char *mnt,
3242
 
              file_info *finfo,
3243
 
              const char *mask,
3244
 
              void *state)
3245
 
{
3246
 
        if (strncmp(finfo->name, ".", 1) != 0 &&
3247
 
            strncmp(finfo->name, "..", 2) != 0) {
3248
 
                
3249
 
                smbc_rmdir_dirempty = False;
3250
 
        }
3251
 
}
3252
 
 
3253
 
/*
3254
 
 * Routine to remove a directory
3255
 
 */
3256
 
 
3257
 
static int
3258
 
smbc_rmdir_ctx(SMBCCTX *context,
3259
 
               const char *fname)
3260
 
{
3261
 
        SMBCSRV *srv;
3262
 
        fstring server;
3263
 
        fstring share;
3264
 
        fstring user;
3265
 
        fstring password;
3266
 
        fstring workgroup;
3267
 
        pstring path;
3268
 
        pstring targetpath;
3269
 
        struct cli_state *targetcli;
3270
 
 
3271
 
        if (!context || !context->internal || 
3272
 
            !context->internal->_initialized) {
3273
 
 
3274
 
                errno = EINVAL;
3275
 
                return -1;
3276
 
 
3277
 
        }
3278
 
 
3279
 
        if (!fname) {
3280
 
 
3281
 
                errno = EINVAL;
3282
 
                return -1;
3283
 
 
3284
 
        }
3285
 
  
3286
 
        DEBUG(4, ("smbc_rmdir(%s)\n", fname));
3287
 
 
3288
 
        if (smbc_parse_path(context, fname,
3289
 
                            workgroup, sizeof(workgroup),
3290
 
                            server, sizeof(server),
3291
 
                            share, sizeof(share),
3292
 
                            path, sizeof(path),
3293
 
                            user, sizeof(user),
3294
 
                            password, sizeof(password),
3295
 
                            NULL, 0))
3296
 
        {
3297
 
                errno = EINVAL;
3298
 
                return -1;
3299
 
        }
3300
 
 
3301
 
        if (user[0] == (char)0) fstrcpy(user, context->user);
3302
 
 
3303
 
        srv = smbc_server(context, True,
3304
 
                          server, share, workgroup, user, password);
3305
 
 
3306
 
        if (!srv) {
3307
 
 
3308
 
                return -1;  /* errno set by smbc_server */
3309
 
 
3310
 
        }
3311
 
 
3312
 
        /*d_printf(">>>rmdir: resolving %s\n", path);*/
3313
 
        if (!cli_resolve_path( "", srv->cli, path, &targetcli, targetpath))
3314
 
        {
3315
 
                d_printf("Could not resolve %s\n", path);
3316
 
                return -1;
3317
 
        }
3318
 
        /*d_printf(">>>rmdir: resolved path as %s\n", targetpath);*/
3319
 
 
3320
 
 
3321
 
        if (!cli_rmdir(targetcli, targetpath)) {
3322
 
 
3323
 
                errno = smbc_errno(context, targetcli);
3324
 
 
3325
 
                if (errno == EACCES) {  /* Check if the dir empty or not */
3326
 
 
3327
 
                        /* Local storage to avoid buffer overflows */
3328
 
                        pstring lpath; 
3329
 
 
3330
 
                        smbc_rmdir_dirempty = True;  /* Make this so ... */
3331
 
 
3332
 
                        pstrcpy(lpath, targetpath);
3333
 
                        pstrcat(lpath, "\\*");
3334
 
 
3335
 
                        if (cli_list(targetcli, lpath,
3336
 
                                     aDIR | aSYSTEM | aHIDDEN,
3337
 
                                     rmdir_list_fn, NULL) < 0) {
3338
 
 
3339
 
                                /* Fix errno to ignore latest error ... */
3340
 
                                DEBUG(5, ("smbc_rmdir: "
3341
 
                                          "cli_list returned an error: %d\n", 
3342
 
                                          smbc_errno(context, targetcli)));
3343
 
                                errno = EACCES;
3344
 
 
3345
 
                        }
3346
 
 
3347
 
                        if (smbc_rmdir_dirempty)
3348
 
                                errno = EACCES;
3349
 
                        else
3350
 
                                errno = ENOTEMPTY;
3351
 
 
3352
 
                }
3353
 
 
3354
 
                return -1;
3355
 
 
3356
 
        } 
3357
 
 
3358
 
        return 0;
3359
 
 
3360
 
}
3361
 
 
3362
 
/*
3363
 
 * Routine to return the current directory position
3364
 
 */
3365
 
 
3366
 
static off_t
3367
 
smbc_telldir_ctx(SMBCCTX *context,
3368
 
                 SMBCFILE *dir)
3369
 
{
3370
 
        off_t ret_val; /* Squash warnings about cast */
3371
 
 
3372
 
        if (!context || !context->internal ||
3373
 
            !context->internal->_initialized) {
3374
 
 
3375
 
                errno = EINVAL;
3376
 
                return -1;
3377
 
 
3378
 
        }
3379
 
 
3380
 
        if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) {
3381
 
 
3382
 
                errno = EBADF;
3383
 
                return -1;
3384
 
 
3385
 
        }
3386
 
 
3387
 
        if (dir->file != False) { /* FIXME, should be dir, perhaps */
3388
 
 
3389
 
                errno = ENOTDIR;
3390
 
                return -1;
3391
 
 
3392
 
        }
3393
 
 
3394
 
        /*
3395
 
         * We return the pointer here as the offset
3396
 
         */
3397
 
        ret_val = (off_t)(long)dir->dir_next;
3398
 
        return ret_val;
3399
 
 
3400
 
}
3401
 
 
3402
 
/*
3403
 
 * A routine to run down the list and see if the entry is OK
3404
 
 */
3405
 
 
3406
 
struct smbc_dir_list *
3407
 
smbc_check_dir_ent(struct smbc_dir_list *list, 
3408
 
                   struct smbc_dirent *dirent)
3409
 
{
3410
 
 
3411
 
        /* Run down the list looking for what we want */
3412
 
 
3413
 
        if (dirent) {
3414
 
 
3415
 
                struct smbc_dir_list *tmp = list;
3416
 
 
3417
 
                while (tmp) {
3418
 
 
3419
 
                        if (tmp->dirent == dirent)
3420
 
                                return tmp;
3421
 
 
3422
 
                        tmp = tmp->next;
3423
 
 
3424
 
                }
3425
 
 
3426
 
        }
3427
 
 
3428
 
        return NULL;  /* Not found, or an error */
3429
 
 
3430
 
}
3431
 
 
3432
 
 
3433
 
/*
3434
 
 * Routine to seek on a directory
3435
 
 */
3436
 
 
3437
 
static int
3438
 
smbc_lseekdir_ctx(SMBCCTX *context,
3439
 
                  SMBCFILE *dir,
3440
 
                  off_t offset)
3441
 
{
3442
 
        long int l_offset = offset;  /* Handle problems of size */
3443
 
        struct smbc_dirent *dirent = (struct smbc_dirent *)l_offset;
3444
 
        struct smbc_dir_list *list_ent = (struct smbc_dir_list *)NULL;
3445
 
 
3446
 
        if (!context || !context->internal ||
3447
 
            !context->internal->_initialized) {
3448
 
 
3449
 
                errno = EINVAL;
3450
 
                return -1;
3451
 
 
3452
 
        }
3453
 
 
3454
 
        if (dir->file != False) { /* FIXME, should be dir, perhaps */
3455
 
 
3456
 
                errno = ENOTDIR;
3457
 
                return -1;
3458
 
 
3459
 
        }
3460
 
 
3461
 
        /* Now, check what we were passed and see if it is OK ... */
3462
 
 
3463
 
        if (dirent == NULL) {  /* Seek to the begining of the list */
3464
 
 
3465
 
                dir->dir_next = dir->dir_list;
3466
 
                return 0;
3467
 
 
3468
 
        }
3469
 
 
3470
 
        /* Now, run down the list and make sure that the entry is OK       */
3471
 
        /* This may need to be changed if we change the format of the list */
3472
 
 
3473
 
        if ((list_ent = smbc_check_dir_ent(dir->dir_list, dirent)) == NULL) {
3474
 
 
3475
 
                errno = EINVAL;   /* Bad entry */
3476
 
                return -1;
3477
 
 
3478
 
        }
3479
 
 
3480
 
        dir->dir_next = list_ent;
3481
 
 
3482
 
        return 0; 
3483
 
 
3484
 
}
3485
 
 
3486
 
/*
3487
 
 * Routine to fstat a dir
3488
 
 */
3489
 
 
3490
 
static int
3491
 
smbc_fstatdir_ctx(SMBCCTX *context,
3492
 
                  SMBCFILE *dir,
3493
 
                  struct stat *st)
3494
 
{
3495
 
 
3496
 
        if (!context || !context->internal || 
3497
 
            !context->internal->_initialized) {
3498
 
 
3499
 
                errno = EINVAL;
3500
 
                return -1;
3501
 
 
3502
 
        }
3503
 
 
3504
 
        /* No code yet ... */
3505
 
 
3506
 
        return 0;
3507
 
 
3508
 
}
3509
 
 
3510
 
static int
3511
 
smbc_chmod_ctx(SMBCCTX *context,
3512
 
               const char *fname,
3513
 
               mode_t newmode)
3514
 
{
3515
 
        SMBCSRV *srv;
3516
 
        fstring server;
3517
 
        fstring share;
3518
 
        fstring user;
3519
 
        fstring password;
3520
 
        fstring workgroup;
3521
 
        pstring path;
3522
 
        uint16 mode;
3523
 
 
3524
 
        if (!context || !context->internal ||
3525
 
            !context->internal->_initialized) {
3526
 
 
3527
 
                errno = EINVAL;  /* Best I can think of ... */
3528
 
                return -1;
3529
 
    
3530
 
        }
3531
 
 
3532
 
        if (!fname) {
3533
 
 
3534
 
                errno = EINVAL;
3535
 
                return -1;
3536
 
 
3537
 
        }
3538
 
  
3539
 
        DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname, newmode));
3540
 
 
3541
 
        if (smbc_parse_path(context, fname,
3542
 
                            workgroup, sizeof(workgroup),
3543
 
                            server, sizeof(server),
3544
 
                            share, sizeof(share),
3545
 
                            path, sizeof(path),
3546
 
                            user, sizeof(user),
3547
 
                            password, sizeof(password),
3548
 
                            NULL, 0)) {
3549
 
                errno = EINVAL;
3550
 
                return -1;
3551
 
        }
3552
 
 
3553
 
        if (user[0] == (char)0) fstrcpy(user, context->user);
3554
 
 
3555
 
        srv = smbc_server(context, True,
3556
 
                          server, share, workgroup, user, password);
3557
 
 
3558
 
        if (!srv) {
3559
 
                return -1;  /* errno set by smbc_server */
3560
 
        }
3561
 
 
3562
 
        mode = 0;
3563
 
 
3564
 
        if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY;
3565
 
        if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH;
3566
 
        if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM;
3567
 
        if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN;
3568
 
 
3569
 
        if (!cli_setatr(srv->cli, path, mode, 0)) {
3570
 
                errno = smbc_errno(context, srv->cli);
3571
 
                return -1;
3572
 
        }
3573
 
        
3574
 
        return 0;
3575
 
}
3576
 
 
3577
 
static int
3578
 
smbc_utimes_ctx(SMBCCTX *context,
3579
 
                const char *fname,
3580
 
                struct timeval *tbuf)
3581
 
{
3582
 
        SMBCSRV *srv;
3583
 
        fstring server;
3584
 
        fstring share;
3585
 
        fstring user;
3586
 
        fstring password;
3587
 
        fstring workgroup;
3588
 
        pstring path;
3589
 
        time_t a_time;
3590
 
        time_t m_time;
3591
 
 
3592
 
        if (!context || !context->internal ||
3593
 
            !context->internal->_initialized) {
3594
 
 
3595
 
                errno = EINVAL;  /* Best I can think of ... */
3596
 
                return -1;
3597
 
    
3598
 
        }
3599
 
 
3600
 
        if (!fname) {
3601
 
 
3602
 
                errno = EINVAL;
3603
 
                return -1;
3604
 
 
3605
 
        }
3606
 
  
3607
 
        if (tbuf == NULL) {
3608
 
                a_time = m_time = time(NULL);
3609
 
        } else {
3610
 
                a_time = tbuf[0].tv_sec;
3611
 
                m_time = tbuf[1].tv_sec;
3612
 
        }
3613
 
 
3614
 
        if (DEBUGLVL(4)) 
3615
 
        {
3616
 
                char *p;
3617
 
                char atimebuf[32];
3618
 
                char mtimebuf[32];
3619
 
 
3620
 
                strncpy(atimebuf, ctime(&a_time), sizeof(atimebuf) - 1);
3621
 
                atimebuf[sizeof(atimebuf) - 1] = '\0';
3622
 
                if ((p = strchr(atimebuf, '\n')) != NULL) {
3623
 
                        *p = '\0';
3624
 
                }
3625
 
 
3626
 
                strncpy(mtimebuf, ctime(&m_time), sizeof(mtimebuf) - 1);
3627
 
                mtimebuf[sizeof(mtimebuf) - 1] = '\0';
3628
 
                if ((p = strchr(mtimebuf, '\n')) != NULL) {
3629
 
                        *p = '\0';
3630
 
                }
3631
 
 
3632
 
                dbgtext("smbc_utimes(%s, atime = %s mtime = %s)\n",
3633
 
                        fname, atimebuf, mtimebuf);
3634
 
        }
3635
 
 
3636
 
        if (smbc_parse_path(context, fname,
3637
 
                            workgroup, sizeof(workgroup),
3638
 
                            server, sizeof(server),
3639
 
                            share, sizeof(share),
3640
 
                            path, sizeof(path),
3641
 
                            user, sizeof(user),
3642
 
                            password, sizeof(password),
3643
 
                            NULL, 0)) {
3644
 
                errno = EINVAL;
3645
 
                return -1;
3646
 
        }
3647
 
 
3648
 
        if (user[0] == (char)0) fstrcpy(user, context->user);
3649
 
 
3650
 
        srv = smbc_server(context, True,
3651
 
                          server, share, workgroup, user, password);
3652
 
 
3653
 
        if (!srv) {
3654
 
                return -1;      /* errno set by smbc_server */
3655
 
        }
3656
 
 
3657
 
        if (!smbc_setatr(context, srv, path, 0, a_time, m_time, 0)) {
3658
 
                return -1;      /* errno set by smbc_setatr */
3659
 
        }
3660
 
 
3661
 
        return 0;
3662
 
}
3663
 
 
3664
 
 
3665
 
/* The MSDN is contradictory over the ordering of ACE entries in an ACL.
3666
 
   However NT4 gives a "The information may have been modified by a
3667
 
   computer running Windows NT 5.0" if denied ACEs do not appear before
3668
 
   allowed ACEs. */
3669
 
 
3670
 
static int
3671
 
ace_compare(SEC_ACE *ace1,
3672
 
            SEC_ACE *ace2)
3673
 
{
3674
 
        if (sec_ace_equal(ace1, ace2)) 
3675
 
                return 0;
3676
 
 
3677
 
        if (ace1->type != ace2->type) 
3678
 
                return ace2->type - ace1->type;
3679
 
 
3680
 
        if (sid_compare(&ace1->trustee, &ace2->trustee)) 
3681
 
                return sid_compare(&ace1->trustee, &ace2->trustee);
3682
 
 
3683
 
        if (ace1->flags != ace2->flags) 
3684
 
                return ace1->flags - ace2->flags;
3685
 
 
3686
 
        if (ace1->info.mask != ace2->info.mask) 
3687
 
                return ace1->info.mask - ace2->info.mask;
3688
 
 
3689
 
        if (ace1->size != ace2->size) 
3690
 
                return ace1->size - ace2->size;
3691
 
 
3692
 
        return memcmp(ace1, ace2, sizeof(SEC_ACE));
3693
 
}
3694
 
 
3695
 
 
3696
 
static void
3697
 
sort_acl(SEC_ACL *the_acl)
3698
 
{
3699
 
        uint32 i;
3700
 
        if (!the_acl) return;
3701
 
 
3702
 
        qsort(the_acl->ace, the_acl->num_aces, sizeof(the_acl->ace[0]),
3703
 
              QSORT_CAST ace_compare);
3704
 
 
3705
 
        for (i=1;i<the_acl->num_aces;) {
3706
 
                if (sec_ace_equal(&the_acl->ace[i-1], &the_acl->ace[i])) {
3707
 
                        int j;
3708
 
                        for (j=i; j<the_acl->num_aces-1; j++) {
3709
 
                                the_acl->ace[j] = the_acl->ace[j+1];
3710
 
                        }
3711
 
                        the_acl->num_aces--;
3712
 
                } else {
3713
 
                        i++;
3714
 
                }
3715
 
        }
3716
 
}
3717
 
 
3718
 
/* convert a SID to a string, either numeric or username/group */
3719
 
static void
3720
 
convert_sid_to_string(struct cli_state *ipc_cli,
3721
 
                      POLICY_HND *pol,
3722
 
                      fstring str,
3723
 
                      BOOL numeric,
3724
 
                      DOM_SID *sid)
3725
 
{
3726
 
        char **domains = NULL;
3727
 
        char **names = NULL;
3728
 
        enum SID_NAME_USE *types = NULL;
3729
 
        struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli);
3730
 
        sid_to_string(str, sid);
3731
 
 
3732
 
        if (numeric) {
3733
 
                return;     /* no lookup desired */
3734
 
        }
3735
 
       
3736
 
        if (!pipe_hnd) {
3737
 
                return;
3738
 
        }
3739
 
 
3740
 
        /* Ask LSA to convert the sid to a name */
3741
 
 
3742
 
        if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_sids(pipe_hnd, ipc_cli->mem_ctx,  
3743
 
                                                 pol, 1, sid, &domains, 
3744
 
                                                 &names, &types)) ||
3745
 
            !domains || !domains[0] || !names || !names[0]) {
3746
 
                return;
3747
 
        }
3748
 
 
3749
 
        /* Converted OK */
3750
 
 
3751
 
        slprintf(str, sizeof(fstring) - 1, "%s%s%s",
3752
 
                 domains[0], lp_winbind_separator(),
3753
 
                 names[0]);
3754
 
}
3755
 
 
3756
 
/* convert a string to a SID, either numeric or username/group */
3757
 
static BOOL
3758
 
convert_string_to_sid(struct cli_state *ipc_cli,
3759
 
                      POLICY_HND *pol,
3760
 
                      BOOL numeric,
3761
 
                      DOM_SID *sid,
3762
 
                      const char *str)
3763
 
{
3764
 
        enum SID_NAME_USE *types = NULL;
3765
 
        DOM_SID *sids = NULL;
3766
 
        BOOL result = True;
3767
 
        struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli);
3768
 
 
3769
 
        if (!pipe_hnd) {
3770
 
                return False;
3771
 
        }
3772
 
 
3773
 
        if (numeric) {
3774
 
                if (strncmp(str, "S-", 2) == 0) {
3775
 
                        return string_to_sid(sid, str);
3776
 
                }
3777
 
 
3778
 
                result = False;
3779
 
                goto done;
3780
 
        }
3781
 
 
3782
 
        if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_names(pipe_hnd, ipc_cli->mem_ctx, 
3783
 
                                                  pol, 1, &str, NULL, &sids, 
3784
 
                                                  &types))) {
3785
 
                result = False;
3786
 
                goto done;
3787
 
        }
3788
 
 
3789
 
        sid_copy(sid, &sids[0]);
3790
 
 done:
3791
 
 
3792
 
        return result;
3793
 
}
3794
 
 
3795
 
 
3796
 
/* parse an ACE in the same format as print_ace() */
3797
 
static BOOL
3798
 
parse_ace(struct cli_state *ipc_cli,
3799
 
          POLICY_HND *pol,
3800
 
          SEC_ACE *ace,
3801
 
          BOOL numeric,
3802
 
          char *str)
3803
 
{
3804
 
        char *p;
3805
 
        const char *cp;
3806
 
        fstring tok;
3807
 
        unsigned int atype;
3808
 
        unsigned int aflags;
3809
 
        unsigned int amask;
3810
 
        DOM_SID sid;
3811
 
        SEC_ACCESS mask;
3812
 
        const struct perm_value *v;
3813
 
        struct perm_value {
3814
 
                const char *perm;
3815
 
                uint32 mask;
3816
 
        };
3817
 
 
3818
 
        /* These values discovered by inspection */
3819
 
        static const struct perm_value special_values[] = {
3820
 
                { "R", 0x00120089 },
3821
 
                { "W", 0x00120116 },
3822
 
                { "X", 0x001200a0 },
3823
 
                { "D", 0x00010000 },
3824
 
                { "P", 0x00040000 },
3825
 
                { "O", 0x00080000 },
3826
 
                { NULL, 0 },
3827
 
        };
3828
 
 
3829
 
        static const struct perm_value standard_values[] = {
3830
 
                { "READ",   0x001200a9 },
3831
 
                { "CHANGE", 0x001301bf },
3832
 
                { "FULL",   0x001f01ff },
3833
 
                { NULL, 0 },
3834
 
        };
3835
 
 
3836
 
 
3837
 
        ZERO_STRUCTP(ace);
3838
 
        p = strchr_m(str,':');
3839
 
        if (!p) return False;
3840
 
        *p = '\0';
3841
 
        p++;
3842
 
        /* Try to parse numeric form */
3843
 
 
3844
 
        if (sscanf(p, "%i/%i/%i", &atype, &aflags, &amask) == 3 &&
3845
 
            convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) {
3846
 
                goto done;
3847
 
        }
3848
 
 
3849
 
        /* Try to parse text form */
3850
 
 
3851
 
        if (!convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) {
3852
 
                return False;
3853
 
        }
3854
 
 
3855
 
        cp = p;
3856
 
        if (!next_token(&cp, tok, "/", sizeof(fstring))) {
3857
 
                return False;
3858
 
        }
3859
 
 
3860
 
        if (StrnCaseCmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) {
3861
 
                atype = SEC_ACE_TYPE_ACCESS_ALLOWED;
3862
 
        } else if (StrnCaseCmp(tok, "DENIED", strlen("DENIED")) == 0) {
3863
 
                atype = SEC_ACE_TYPE_ACCESS_DENIED;
3864
 
        } else {
3865
 
                return False;
3866
 
        }
3867
 
 
3868
 
        /* Only numeric form accepted for flags at present */
3869
 
 
3870
 
        if (!(next_token(&cp, tok, "/", sizeof(fstring)) &&
3871
 
              sscanf(tok, "%i", &aflags))) {
3872
 
                return False;
3873
 
        }
3874
 
 
3875
 
        if (!next_token(&cp, tok, "/", sizeof(fstring))) {
3876
 
                return False;
3877
 
        }
3878
 
 
3879
 
        if (strncmp(tok, "0x", 2) == 0) {
3880
 
                if (sscanf(tok, "%i", &amask) != 1) {
3881
 
                        return False;
3882
 
                }
3883
 
                goto done;
3884
 
        }
3885
 
 
3886
 
        for (v = standard_values; v->perm; v++) {
3887
 
                if (strcmp(tok, v->perm) == 0) {
3888
 
                        amask = v->mask;
3889
 
                        goto done;
3890
 
                }
3891
 
        }
3892
 
 
3893
 
        p = tok;
3894
 
 
3895
 
        while(*p) {
3896
 
                BOOL found = False;
3897
 
 
3898
 
                for (v = special_values; v->perm; v++) {
3899
 
                        if (v->perm[0] == *p) {
3900
 
                                amask |= v->mask;
3901
 
                                found = True;
3902
 
                        }
3903
 
                }
3904
 
 
3905
 
                if (!found) return False;
3906
 
                p++;
3907
 
        }
3908
 
 
3909
 
        if (*p) {
3910
 
                return False;
3911
 
        }
3912
 
 
3913
 
 done:
3914
 
        mask.mask = amask;
3915
 
        init_sec_ace(ace, &sid, atype, mask, aflags);
3916
 
        return True;
3917
 
}
3918
 
 
3919
 
/* add an ACE to a list of ACEs in a SEC_ACL */
3920
 
static BOOL
3921
 
add_ace(SEC_ACL **the_acl,
3922
 
        SEC_ACE *ace,
3923
 
        TALLOC_CTX *ctx)
3924
 
{
3925
 
        SEC_ACL *newacl;
3926
 
        SEC_ACE *aces;
3927
 
 
3928
 
        if (! *the_acl) {
3929
 
                (*the_acl) = make_sec_acl(ctx, 3, 1, ace);
3930
 
                return True;
3931
 
        }
3932
 
 
3933
 
        if ((aces = SMB_CALLOC_ARRAY(SEC_ACE, 1+(*the_acl)->num_aces)) == NULL) {
3934
 
                return False;
3935
 
        }
3936
 
        memcpy(aces, (*the_acl)->ace, (*the_acl)->num_aces * sizeof(SEC_ACE));
3937
 
        memcpy(aces+(*the_acl)->num_aces, ace, sizeof(SEC_ACE));
3938
 
        newacl = make_sec_acl(ctx, (*the_acl)->revision,
3939
 
                              1+(*the_acl)->num_aces, aces);
3940
 
        SAFE_FREE(aces);
3941
 
        (*the_acl) = newacl;
3942
 
        return True;
3943
 
}
3944
 
 
3945
 
 
3946
 
/* parse a ascii version of a security descriptor */
3947
 
static SEC_DESC *
3948
 
sec_desc_parse(TALLOC_CTX *ctx,
3949
 
               struct cli_state *ipc_cli,
3950
 
               POLICY_HND *pol,
3951
 
               BOOL numeric,
3952
 
               char *str)
3953
 
{
3954
 
        const char *p = str;
3955
 
        fstring tok;
3956
 
        SEC_DESC *ret = NULL;
3957
 
        size_t sd_size;
3958
 
        DOM_SID *grp_sid=NULL;
3959
 
        DOM_SID *owner_sid=NULL;
3960
 
        SEC_ACL *dacl=NULL;
3961
 
        int revision=1;
3962
 
 
3963
 
        while (next_token(&p, tok, "\t,\r\n", sizeof(tok))) {
3964
 
 
3965
 
                if (StrnCaseCmp(tok,"REVISION:", 9) == 0) {
3966
 
                        revision = strtol(tok+9, NULL, 16);
3967
 
                        continue;
3968
 
                }
3969
 
 
3970
 
                if (StrnCaseCmp(tok,"OWNER:", 6) == 0) {
3971
 
                        if (owner_sid) {
3972
 
                                DEBUG(5, ("OWNER specified more than once!\n"));
3973
 
                                goto done;
3974
 
                        }
3975
 
                        owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
3976
 
                        if (!owner_sid ||
3977
 
                            !convert_string_to_sid(ipc_cli, pol,
3978
 
                                                   numeric,
3979
 
                                                   owner_sid, tok+6)) {
3980
 
                                DEBUG(5, ("Failed to parse owner sid\n"));
3981
 
                                goto done;
3982
 
                        }
3983
 
                        continue;
3984
 
                }
3985
 
 
3986
 
                if (StrnCaseCmp(tok,"OWNER+:", 7) == 0) {
3987
 
                        if (owner_sid) {
3988
 
                                DEBUG(5, ("OWNER specified more than once!\n"));
3989
 
                                goto done;
3990
 
                        }
3991
 
                        owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
3992
 
                        if (!owner_sid ||
3993
 
                            !convert_string_to_sid(ipc_cli, pol,
3994
 
                                                   False,
3995
 
                                                   owner_sid, tok+7)) {
3996
 
                                DEBUG(5, ("Failed to parse owner sid\n"));
3997
 
                                goto done;
3998
 
                        }
3999
 
                        continue;
4000
 
                }
4001
 
 
4002
 
                if (StrnCaseCmp(tok,"GROUP:", 6) == 0) {
4003
 
                        if (grp_sid) {
4004
 
                                DEBUG(5, ("GROUP specified more than once!\n"));
4005
 
                                goto done;
4006
 
                        }
4007
 
                        grp_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
4008
 
                        if (!grp_sid ||
4009
 
                            !convert_string_to_sid(ipc_cli, pol,
4010
 
                                                   numeric,
4011
 
                                                   grp_sid, tok+6)) {
4012
 
                                DEBUG(5, ("Failed to parse group sid\n"));
4013
 
                                goto done;
4014
 
                        }
4015
 
                        continue;
4016
 
                }
4017
 
 
4018
 
                if (StrnCaseCmp(tok,"GROUP+:", 7) == 0) {
4019
 
                        if (grp_sid) {
4020
 
                                DEBUG(5, ("GROUP specified more than once!\n"));
4021
 
                                goto done;
4022
 
                        }
4023
 
                        grp_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
4024
 
                        if (!grp_sid ||
4025
 
                            !convert_string_to_sid(ipc_cli, pol,
4026
 
                                                   False,
4027
 
                                                   grp_sid, tok+6)) {
4028
 
                                DEBUG(5, ("Failed to parse group sid\n"));
4029
 
                                goto done;
4030
 
                        }
4031
 
                        continue;
4032
 
                }
4033
 
 
4034
 
                if (StrnCaseCmp(tok,"ACL:", 4) == 0) {
4035
 
                        SEC_ACE ace;
4036
 
                        if (!parse_ace(ipc_cli, pol, &ace, numeric, tok+4)) {
4037
 
                                DEBUG(5, ("Failed to parse ACL %s\n", tok));
4038
 
                                goto done;
4039
 
                        }
4040
 
                        if(!add_ace(&dacl, &ace, ctx)) {
4041
 
                                DEBUG(5, ("Failed to add ACL %s\n", tok));
4042
 
                                goto done;
4043
 
                        }
4044
 
                        continue;
4045
 
                }
4046
 
 
4047
 
                if (StrnCaseCmp(tok,"ACL+:", 5) == 0) {
4048
 
                        SEC_ACE ace;
4049
 
                        if (!parse_ace(ipc_cli, pol, &ace, False, tok+5)) {
4050
 
                                DEBUG(5, ("Failed to parse ACL %s\n", tok));
4051
 
                                goto done;
4052
 
                        }
4053
 
                        if(!add_ace(&dacl, &ace, ctx)) {
4054
 
                                DEBUG(5, ("Failed to add ACL %s\n", tok));
4055
 
                                goto done;
4056
 
                        }
4057
 
                        continue;
4058
 
                }
4059
 
 
4060
 
                DEBUG(5, ("Failed to parse security descriptor\n"));
4061
 
                goto done;
4062
 
        }
4063
 
 
4064
 
        ret = make_sec_desc(ctx, revision, SEC_DESC_SELF_RELATIVE, 
4065
 
                            owner_sid, grp_sid, NULL, dacl, &sd_size);
4066
 
 
4067
 
  done:
4068
 
        SAFE_FREE(grp_sid);
4069
 
        SAFE_FREE(owner_sid);
4070
 
 
4071
 
        return ret;
4072
 
}
4073
 
 
4074
 
 
4075
 
/* Obtain the current dos attributes */
4076
 
static DOS_ATTR_DESC *
4077
 
dos_attr_query(SMBCCTX *context,
4078
 
               TALLOC_CTX *ctx,
4079
 
               const char *filename,
4080
 
               SMBCSRV *srv)
4081
 
{
4082
 
        time_t m_time = 0, a_time = 0, c_time = 0;
4083
 
        SMB_OFF_T size = 0;
4084
 
        uint16 mode = 0;
4085
 
        SMB_INO_T inode = 0;
4086
 
        DOS_ATTR_DESC *ret;
4087
 
    
4088
 
        ret = TALLOC_P(ctx, DOS_ATTR_DESC);
4089
 
        if (!ret) {
4090
 
                errno = ENOMEM;
4091
 
                return NULL;
4092
 
        }
4093
 
 
4094
 
        /* Obtain the DOS attributes */
4095
 
        if (!smbc_getatr(context, srv, CONST_DISCARD(char *, filename),
4096
 
                         &mode, &size, 
4097
 
                         &c_time, &a_time, &m_time, &inode)) {
4098
 
        
4099
 
                errno = smbc_errno(context, srv->cli);
4100
 
                DEBUG(5, ("dos_attr_query Failed to query old attributes\n"));
4101
 
                return NULL;
4102
 
        
4103
 
        }
4104
 
                
4105
 
        ret->mode = mode;
4106
 
        ret->size = size;
4107
 
        ret->a_time = a_time;
4108
 
        ret->c_time = c_time;
4109
 
        ret->m_time = m_time;
4110
 
        ret->inode = inode;
4111
 
 
4112
 
        return ret;
4113
 
}
4114
 
 
4115
 
 
4116
 
/* parse a ascii version of a security descriptor */
4117
 
static void
4118
 
dos_attr_parse(SMBCCTX *context,
4119
 
               DOS_ATTR_DESC *dad,
4120
 
               SMBCSRV *srv,
4121
 
               char *str)
4122
 
{
4123
 
        const char *p = str;
4124
 
        fstring tok;
4125
 
 
4126
 
        while (next_token(&p, tok, "\t,\r\n", sizeof(tok))) {
4127
 
 
4128
 
                if (StrnCaseCmp(tok, "MODE:", 5) == 0) {
4129
 
                        dad->mode = strtol(tok+5, NULL, 16);
4130
 
                        continue;
4131
 
                }
4132
 
 
4133
 
                if (StrnCaseCmp(tok, "SIZE:", 5) == 0) {
4134
 
                        dad->size = (SMB_OFF_T)atof(tok+5);
4135
 
                        continue;
4136
 
                }
4137
 
 
4138
 
                if (StrnCaseCmp(tok, "A_TIME:", 7) == 0) {
4139
 
                        dad->a_time = (time_t)strtol(tok+7, NULL, 10);
4140
 
                        continue;
4141
 
                }
4142
 
 
4143
 
                if (StrnCaseCmp(tok, "C_TIME:", 7) == 0) {
4144
 
                        dad->c_time = (time_t)strtol(tok+7, NULL, 10);
4145
 
                        continue;
4146
 
                }
4147
 
 
4148
 
                if (StrnCaseCmp(tok, "M_TIME:", 7) == 0) {
4149
 
                        dad->m_time = (time_t)strtol(tok+7, NULL, 10);
4150
 
                        continue;
4151
 
                }
4152
 
 
4153
 
                if (StrnCaseCmp(tok, "INODE:", 6) == 0) {
4154
 
                        dad->inode = (SMB_INO_T)atof(tok+6);
4155
 
                        continue;
4156
 
                }
4157
 
        }
4158
 
}
4159
 
 
4160
 
/***************************************************** 
4161
 
 Retrieve the acls for a file.
4162
 
*******************************************************/
4163
 
 
4164
 
static int
4165
 
cacl_get(SMBCCTX *context,
4166
 
         TALLOC_CTX *ctx,
4167
 
         SMBCSRV *srv,
4168
 
         struct cli_state *ipc_cli,
4169
 
         POLICY_HND *pol,
4170
 
         char *filename,
4171
 
         char *attr_name,
4172
 
         char *buf,
4173
 
         int bufsize)
4174
 
{
4175
 
        uint32 i;
4176
 
        int n = 0;
4177
 
        int n_used;
4178
 
        BOOL all;
4179
 
        BOOL all_nt;
4180
 
        BOOL all_nt_acls;
4181
 
        BOOL all_dos;
4182
 
        BOOL some_nt;
4183
 
        BOOL some_dos;
4184
 
        BOOL exclude_nt_revision = False;
4185
 
        BOOL exclude_nt_owner = False;
4186
 
        BOOL exclude_nt_group = False;
4187
 
        BOOL exclude_nt_acl = False;
4188
 
        BOOL exclude_dos_mode = False;
4189
 
        BOOL exclude_dos_size = False;
4190
 
        BOOL exclude_dos_ctime = False;
4191
 
        BOOL exclude_dos_atime = False;
4192
 
        BOOL exclude_dos_mtime = False;
4193
 
        BOOL exclude_dos_inode = False;
4194
 
        BOOL numeric = True;
4195
 
        BOOL determine_size = (bufsize == 0);
4196
 
        int fnum = -1;
4197
 
        SEC_DESC *sd;
4198
 
        fstring sidstr;
4199
 
        fstring name_sandbox;
4200
 
        char *name;
4201
 
        char *pExclude;
4202
 
        char *p;
4203
 
        time_t m_time = 0, a_time = 0, c_time = 0;
4204
 
        SMB_OFF_T size = 0;
4205
 
        uint16 mode = 0;
4206
 
        SMB_INO_T ino = 0;
4207
 
        struct cli_state *cli = srv->cli;
4208
 
 
4209
 
        /* Copy name so we can strip off exclusions (if any are specified) */
4210
 
        strncpy(name_sandbox, attr_name, sizeof(name_sandbox) - 1);
4211
 
 
4212
 
        /* Ensure name is null terminated */
4213
 
        name_sandbox[sizeof(name_sandbox) - 1] = '\0';
4214
 
 
4215
 
        /* Play in the sandbox */
4216
 
        name = name_sandbox;
4217
 
 
4218
 
        /* If there are any exclusions, point to them and mask them from name */
4219
 
        if ((pExclude = strchr(name, '!')) != NULL)
4220
 
        {
4221
 
                *pExclude++ = '\0';
4222
 
        }
4223
 
 
4224
 
        all = (StrnCaseCmp(name, "system.*", 8) == 0);
4225
 
        all_nt = (StrnCaseCmp(name, "system.nt_sec_desc.*", 20) == 0);
4226
 
        all_nt_acls = (StrnCaseCmp(name, "system.nt_sec_desc.acl.*", 24) == 0);
4227
 
        all_dos = (StrnCaseCmp(name, "system.dos_attr.*", 17) == 0);
4228
 
        some_nt = (StrnCaseCmp(name, "system.nt_sec_desc.", 19) == 0);
4229
 
        some_dos = (StrnCaseCmp(name, "system.dos_attr.", 16) == 0);
4230
 
        numeric = (* (name + strlen(name) - 1) != '+');
4231
 
 
4232
 
        /* Look for exclusions from "all" requests */
4233
 
        if (all || all_nt || all_dos) {
4234
 
 
4235
 
                /* Exclusions are delimited by '!' */
4236
 
                for (;
4237
 
                     pExclude != NULL;
4238
 
                     pExclude = (p == NULL ? NULL : p + 1)) {
4239
 
 
4240
 
                /* Find end of this exclusion name */
4241
 
                if ((p = strchr(pExclude, '!')) != NULL)
4242
 
                {
4243
 
                    *p = '\0';
4244
 
                }
4245
 
 
4246
 
                /* Which exclusion name is this? */
4247
 
                if (StrCaseCmp(pExclude, "nt_sec_desc.revision") == 0) {
4248
 
                    exclude_nt_revision = True;
4249
 
                }
4250
 
                else if (StrCaseCmp(pExclude, "nt_sec_desc.owner") == 0) {
4251
 
                    exclude_nt_owner = True;
4252
 
                }
4253
 
                else if (StrCaseCmp(pExclude, "nt_sec_desc.group") == 0) {
4254
 
                    exclude_nt_group = True;
4255
 
                }
4256
 
                else if (StrCaseCmp(pExclude, "nt_sec_desc.acl") == 0) {
4257
 
                    exclude_nt_acl = True;
4258
 
                }
4259
 
                else if (StrCaseCmp(pExclude, "dos_attr.mode") == 0) {
4260
 
                    exclude_dos_mode = True;
4261
 
                }
4262
 
                else if (StrCaseCmp(pExclude, "dos_attr.size") == 0) {
4263
 
                    exclude_dos_size = True;
4264
 
                }
4265
 
                else if (StrCaseCmp(pExclude, "dos_attr.c_time") == 0) {
4266
 
                    exclude_dos_ctime = True;
4267
 
                }
4268
 
                else if (StrCaseCmp(pExclude, "dos_attr.a_time") == 0) {
4269
 
                    exclude_dos_atime = True;
4270
 
                }
4271
 
                else if (StrCaseCmp(pExclude, "dos_attr.m_time") == 0) {
4272
 
                    exclude_dos_mtime = True;
4273
 
                }
4274
 
                else if (StrCaseCmp(pExclude, "dos_attr.inode") == 0) {
4275
 
                    exclude_dos_inode = True;
4276
 
                }
4277
 
                else {
4278
 
                    DEBUG(5, ("cacl_get received unknown exclusion: %s\n",
4279
 
                              pExclude));
4280
 
                    errno = ENOATTR;
4281
 
                    return -1;
4282
 
                }
4283
 
            }
4284
 
        }
4285
 
 
4286
 
        n_used = 0;
4287
 
 
4288
 
        /*
4289
 
         * If we are (possibly) talking to an NT or new system and some NT
4290
 
         * attributes have been requested...
4291
 
         */
4292
 
        if (ipc_cli && (all || some_nt || all_nt_acls)) {
4293
 
                /* Point to the portion after "system.nt_sec_desc." */
4294
 
                name += 19;     /* if (all) this will be invalid but unused */
4295
 
 
4296
 
                /* ... then obtain any NT attributes which were requested */
4297
 
                fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ);
4298
 
 
4299
 
                if (fnum == -1) {
4300
 
                        DEBUG(5, ("cacl_get failed to open %s: %s\n",
4301
 
                                  filename, cli_errstr(cli)));
4302
 
                        errno = 0;
4303
 
                        return -1;
4304
 
                }
4305
 
 
4306
 
                sd = cli_query_secdesc(cli, fnum, ctx);
4307
 
 
4308
 
                if (!sd) {
4309
 
                        DEBUG(5,
4310
 
                              ("cacl_get Failed to query old descriptor\n"));
4311
 
                        errno = 0;
4312
 
                        return -1;
4313
 
                }
4314
 
 
4315
 
                cli_close(cli, fnum);
4316
 
 
4317
 
                if (! exclude_nt_revision) {
4318
 
                        if (all || all_nt) {
4319
 
                                if (determine_size) {
4320
 
                                        p = talloc_asprintf(ctx,
4321
 
                                                            "REVISION:%d",
4322
 
                                                            sd->revision);
4323
 
                                        if (!p) {
4324
 
                                                errno = ENOMEM;
4325
 
                                                return -1;
4326
 
                                        }
4327
 
                                        n = strlen(p);
4328
 
                                } else {
4329
 
                                        n = snprintf(buf, bufsize,
4330
 
                                                     "REVISION:%d",
4331
 
                                                     sd->revision);
4332
 
                                }
4333
 
                        } else if (StrCaseCmp(name, "revision") == 0) {
4334
 
                                if (determine_size) {
4335
 
                                        p = talloc_asprintf(ctx, "%d",
4336
 
                                                            sd->revision);
4337
 
                                        if (!p) {
4338
 
                                                errno = ENOMEM;
4339
 
                                                return -1;
4340
 
                                        }
4341
 
                                        n = strlen(p);
4342
 
                                } else {
4343
 
                                        n = snprintf(buf, bufsize, "%d",
4344
 
                                                     sd->revision);
4345
 
                                }
4346
 
                        }
4347
 
        
4348
 
                        if (!determine_size && n > bufsize) {
4349
 
                                errno = ERANGE;
4350
 
                                return -1;
4351
 
                        }
4352
 
                        buf += n;
4353
 
                        n_used += n;
4354
 
                        bufsize -= n;
4355
 
                }
4356
 
 
4357
 
                if (! exclude_nt_owner) {
4358
 
                        /* Get owner and group sid */
4359
 
                        if (sd->owner_sid) {
4360
 
                                convert_sid_to_string(ipc_cli, pol,
4361
 
                                                      sidstr,
4362
 
                                                      numeric,
4363
 
                                                      sd->owner_sid);
4364
 
                        } else {
4365
 
                                fstrcpy(sidstr, "");
4366
 
                        }
4367
 
 
4368
 
                        if (all || all_nt) {
4369
 
                                if (determine_size) {
4370
 
                                        p = talloc_asprintf(ctx, ",OWNER:%s",
4371
 
                                                            sidstr);
4372
 
                                        if (!p) {
4373
 
                                                errno = ENOMEM;
4374
 
                                                return -1;
4375
 
                                        }
4376
 
                                        n = strlen(p);
4377
 
                                } else {
4378
 
                                        n = snprintf(buf, bufsize,
4379
 
                                                     ",OWNER:%s", sidstr);
4380
 
                                }
4381
 
                        } else if (StrnCaseCmp(name, "owner", 5) == 0) {
4382
 
                                if (determine_size) {
4383
 
                                        p = talloc_asprintf(ctx, "%s", sidstr);
4384
 
                                        if (!p) {
4385
 
                                                errno = ENOMEM;
4386
 
                                                return -1;
4387
 
                                        }
4388
 
                                        n = strlen(p);
4389
 
                                } else {
4390
 
                                        n = snprintf(buf, bufsize, "%s",
4391
 
                                                     sidstr);
4392
 
                                }
4393
 
                        }
4394
 
 
4395
 
                        if (!determine_size && n > bufsize) {
4396
 
                                errno = ERANGE;
4397
 
                                return -1;
4398
 
                        }
4399
 
                        buf += n;
4400
 
                        n_used += n;
4401
 
                        bufsize -= n;
4402
 
                }
4403
 
 
4404
 
                if (! exclude_nt_group) {
4405
 
                        if (sd->grp_sid) {
4406
 
                                convert_sid_to_string(ipc_cli, pol,
4407
 
                                                      sidstr, numeric,
4408
 
                                                      sd->grp_sid);
4409
 
                        } else {
4410
 
                                fstrcpy(sidstr, "");
4411
 
                        }
4412
 
 
4413
 
                        if (all || all_nt) {
4414
 
                                if (determine_size) {
4415
 
                                        p = talloc_asprintf(ctx, ",GROUP:%s",
4416
 
                                                            sidstr);
4417
 
                                        if (!p) {
4418
 
                                                errno = ENOMEM;
4419
 
                                                return -1;
4420
 
                                        }
4421
 
                                        n = strlen(p);
4422
 
                                } else {
4423
 
                                        n = snprintf(buf, bufsize,
4424
 
                                                     ",GROUP:%s", sidstr);
4425
 
                                }
4426
 
                        } else if (StrnCaseCmp(name, "group", 5) == 0) {
4427
 
                                if (determine_size) {
4428
 
                                        p = talloc_asprintf(ctx, "%s", sidstr);
4429
 
                                        if (!p) {
4430
 
                                                errno = ENOMEM;
4431
 
                                                return -1;
4432
 
                                        }
4433
 
                                        n = strlen(p);
4434
 
                                } else {
4435
 
                                        n = snprintf(buf, bufsize,
4436
 
                                                     "%s", sidstr);
4437
 
                                }
4438
 
                        }
4439
 
 
4440
 
                        if (!determine_size && n > bufsize) {
4441
 
                                errno = ERANGE;
4442
 
                                return -1;
4443
 
                        }
4444
 
                        buf += n;
4445
 
                        n_used += n;
4446
 
                        bufsize -= n;
4447
 
                }
4448
 
 
4449
 
                if (! exclude_nt_acl) {
4450
 
                        /* Add aces to value buffer  */
4451
 
                        for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
4452
 
 
4453
 
                                SEC_ACE *ace = &sd->dacl->ace[i];
4454
 
                                convert_sid_to_string(ipc_cli, pol,
4455
 
                                                      sidstr, numeric,
4456
 
                                                      &ace->trustee);
4457
 
 
4458
 
                                if (all || all_nt) {
4459
 
                                        if (determine_size) {
4460
 
                                                p = talloc_asprintf(
4461
 
                                                        ctx, 
4462
 
                                                        ",ACL:"
4463
 
                                                        "%s:%d/%d/0x%08x", 
4464
 
                                                        sidstr,
4465
 
                                                        ace->type,
4466
 
                                                        ace->flags,
4467
 
                                                        ace->info.mask);
4468
 
                                                if (!p) {
4469
 
                                                        errno = ENOMEM;
4470
 
                                                        return -1;
4471
 
                                                }
4472
 
                                                n = strlen(p);
4473
 
                                        } else {
4474
 
                                                n = snprintf(
4475
 
                                                        buf, bufsize,
4476
 
                                                        ",ACL:%s:%d/%d/0x%08x", 
4477
 
                                                        sidstr,
4478
 
                                                        ace->type,
4479
 
                                                        ace->flags,
4480
 
                                                        ace->info.mask);
4481
 
                                        }
4482
 
                                } else if ((StrnCaseCmp(name, "acl", 3) == 0 &&
4483
 
                                            StrCaseCmp(name+3, sidstr) == 0) ||
4484
 
                                           (StrnCaseCmp(name, "acl+", 4) == 0 &&
4485
 
                                            StrCaseCmp(name+4, sidstr) == 0)) {
4486
 
                                        if (determine_size) {
4487
 
                                                p = talloc_asprintf(
4488
 
                                                        ctx, 
4489
 
                                                        "%d/%d/0x%08x", 
4490
 
                                                        ace->type,
4491
 
                                                        ace->flags,
4492
 
                                                        ace->info.mask);
4493
 
                                                if (!p) {
4494
 
                                                        errno = ENOMEM;
4495
 
                                                        return -1;
4496
 
                                                }
4497
 
                                                n = strlen(p);
4498
 
                                        } else {
4499
 
                                                n = snprintf(buf, bufsize,
4500
 
                                                             "%d/%d/0x%08x", 
4501
 
                                                             ace->type,
4502
 
                                                             ace->flags,
4503
 
                                                             ace->info.mask);
4504
 
                                        }
4505
 
                                } else if (all_nt_acls) {
4506
 
                                        if (determine_size) {
4507
 
                                                p = talloc_asprintf(
4508
 
                                                        ctx, 
4509
 
                                                        "%s%s:%d/%d/0x%08x",
4510
 
                                                        i ? "," : "",
4511
 
                                                        sidstr,
4512
 
                                                        ace->type,
4513
 
                                                        ace->flags,
4514
 
                                                        ace->info.mask);
4515
 
                                                if (!p) {
4516
 
                                                        errno = ENOMEM;
4517
 
                                                        return -1;
4518
 
                                                }
4519
 
                                                n = strlen(p);
4520
 
                                        } else {
4521
 
                                                n = snprintf(buf, bufsize,
4522
 
                                                             "%s%s:%d/%d/0x%08x",
4523
 
                                                             i ? "," : "",
4524
 
                                                             sidstr,
4525
 
                                                             ace->type,
4526
 
                                                             ace->flags,
4527
 
                                                             ace->info.mask);
4528
 
                                        }
4529
 
                                }
4530
 
                                if (n > bufsize) {
4531
 
                                        errno = ERANGE;
4532
 
                                        return -1;
4533
 
                                }
4534
 
                                buf += n;
4535
 
                                n_used += n;
4536
 
                                bufsize -= n;
4537
 
                        }
4538
 
                }
4539
 
 
4540
 
                /* Restore name pointer to its original value */
4541
 
                name -= 19;
4542
 
        }
4543
 
 
4544
 
        if (all || some_dos) {
4545
 
                /* Point to the portion after "system.dos_attr." */
4546
 
                name += 16;     /* if (all) this will be invalid but unused */
4547
 
 
4548
 
                /* Obtain the DOS attributes */
4549
 
                if (!smbc_getatr(context, srv, filename, &mode, &size, 
4550
 
                                 &c_time, &a_time, &m_time, &ino)) {
4551
 
                        
4552
 
                        errno = smbc_errno(context, srv->cli);
4553
 
                        return -1;
4554
 
                        
4555
 
                }
4556
 
                
4557
 
                if (! exclude_dos_mode) {
4558
 
                        if (all || all_dos) {
4559
 
                                if (determine_size) {
4560
 
                                        p = talloc_asprintf(ctx,
4561
 
                                                            "%sMODE:0x%x",
4562
 
                                                            (ipc_cli &&
4563
 
                                                             (all || some_nt)
4564
 
                                                             ? ","
4565
 
                                                             : ""),
4566
 
                                                            mode);
4567
 
                                        if (!p) {
4568
 
                                                errno = ENOMEM;
4569
 
                                                return -1;
4570
 
                                        }
4571
 
                                        n = strlen(p);
4572
 
                                } else {
4573
 
                                        n = snprintf(buf, bufsize,
4574
 
                                                     "%sMODE:0x%x",
4575
 
                                                     (ipc_cli &&
4576
 
                                                      (all || some_nt)
4577
 
                                                      ? ","
4578
 
                                                      : ""),
4579
 
                                                     mode);
4580
 
                                }
4581
 
                        } else if (StrCaseCmp(name, "mode") == 0) {
4582
 
                                if (determine_size) {
4583
 
                                        p = talloc_asprintf(ctx, "0x%x", mode);
4584
 
                                        if (!p) {
4585
 
                                                errno = ENOMEM;
4586
 
                                                return -1;
4587
 
                                        }
4588
 
                                        n = strlen(p);
4589
 
                                } else {
4590
 
                                        n = snprintf(buf, bufsize,
4591
 
                                                     "0x%x", mode);
4592
 
                                }
4593
 
                        }
4594
 
        
4595
 
                        if (!determine_size && n > bufsize) {
4596
 
                                errno = ERANGE;
4597
 
                                return -1;
4598
 
                        }
4599
 
                        buf += n;
4600
 
                        n_used += n;
4601
 
                        bufsize -= n;
4602
 
                }
4603
 
 
4604
 
                if (! exclude_dos_size) {
4605
 
                        if (all || all_dos) {
4606
 
                                if (determine_size) {
4607
 
                                        p = talloc_asprintf(
4608
 
                                                ctx,
4609
 
                                                ",SIZE:%.0f",
4610
 
                                                (double)size);
4611
 
                                        if (!p) {
4612
 
                                                errno = ENOMEM;
4613
 
                                                return -1;
4614
 
                                        }
4615
 
                                        n = strlen(p);
4616
 
                                } else {
4617
 
                                        n = snprintf(buf, bufsize,
4618
 
                                                     ",SIZE:%.0f",
4619
 
                                                     (double)size);
4620
 
                                }
4621
 
                        } else if (StrCaseCmp(name, "size") == 0) {
4622
 
                                if (determine_size) {
4623
 
                                        p = talloc_asprintf(
4624
 
                                                ctx,
4625
 
                                                "%.0f",
4626
 
                                                (double)size);
4627
 
                                        if (!p) {
4628
 
                                                errno = ENOMEM;
4629
 
                                                return -1;
4630
 
                                        }
4631
 
                                        n = strlen(p);
4632
 
                                } else {
4633
 
                                        n = snprintf(buf, bufsize,
4634
 
                                                     "%.0f",
4635
 
                                                     (double)size);
4636
 
                                }
4637
 
                        }
4638
 
        
4639
 
                        if (!determine_size && n > bufsize) {
4640
 
                                errno = ERANGE;
4641
 
                                return -1;
4642
 
                        }
4643
 
                        buf += n;
4644
 
                        n_used += n;
4645
 
                        bufsize -= n;
4646
 
                }
4647
 
 
4648
 
                if (! exclude_dos_ctime) {
4649
 
                        if (all || all_dos) {
4650
 
                                if (determine_size) {
4651
 
                                        p = talloc_asprintf(ctx,
4652
 
                                                            ",C_TIME:%lu",
4653
 
                                                            c_time);
4654
 
                                        if (!p) {
4655
 
                                                errno = ENOMEM;
4656
 
                                                return -1;
4657
 
                                        }
4658
 
                                        n = strlen(p);
4659
 
                                } else {
4660
 
                                        n = snprintf(buf, bufsize,
4661
 
                                                     ",C_TIME:%lu", c_time);
4662
 
                                }
4663
 
                        } else if (StrCaseCmp(name, "c_time") == 0) {
4664
 
                                if (determine_size) {
4665
 
                                        p = talloc_asprintf(ctx, "%lu", c_time);
4666
 
                                        if (!p) {
4667
 
                                                errno = ENOMEM;
4668
 
                                                return -1;
4669
 
                                        }
4670
 
                                        n = strlen(p);
4671
 
                                } else {
4672
 
                                        n = snprintf(buf, bufsize,
4673
 
                                                     "%lu", c_time);
4674
 
                                }
4675
 
                        }
4676
 
        
4677
 
                        if (!determine_size && n > bufsize) {
4678
 
                                errno = ERANGE;
4679
 
                                return -1;
4680
 
                        }
4681
 
                        buf += n;
4682
 
                        n_used += n;
4683
 
                        bufsize -= n;
4684
 
                }
4685
 
 
4686
 
                if (! exclude_dos_atime) {
4687
 
                        if (all || all_dos) {
4688
 
                                if (determine_size) {
4689
 
                                        p = talloc_asprintf(ctx,
4690
 
                                                            ",A_TIME:%lu",
4691
 
                                                            a_time);
4692
 
                                        if (!p) {
4693
 
                                                errno = ENOMEM;
4694
 
                                                return -1;
4695
 
                                        }
4696
 
                                        n = strlen(p);
4697
 
                                } else {
4698
 
                                        n = snprintf(buf, bufsize,
4699
 
                                                     ",A_TIME:%lu", a_time);
4700
 
                                }
4701
 
                        } else if (StrCaseCmp(name, "a_time") == 0) {
4702
 
                                if (determine_size) {
4703
 
                                        p = talloc_asprintf(ctx, "%lu", a_time);
4704
 
                                        if (!p) {
4705
 
                                                errno = ENOMEM;
4706
 
                                                return -1;
4707
 
                                        }
4708
 
                                        n = strlen(p);
4709
 
                                } else {
4710
 
                                        n = snprintf(buf, bufsize,
4711
 
                                                     "%lu", a_time);
4712
 
                                }
4713
 
                        }
4714
 
        
4715
 
                        if (!determine_size && n > bufsize) {
4716
 
                                errno = ERANGE;
4717
 
                                return -1;
4718
 
                        }
4719
 
                        buf += n;
4720
 
                        n_used += n;
4721
 
                        bufsize -= n;
4722
 
                }
4723
 
 
4724
 
                if (! exclude_dos_mtime) {
4725
 
                        if (all || all_dos) {
4726
 
                                if (determine_size) {
4727
 
                                        p = talloc_asprintf(ctx,
4728
 
                                                            ",M_TIME:%lu",
4729
 
                                                            m_time);
4730
 
                                        if (!p) {
4731
 
                                                errno = ENOMEM;
4732
 
                                                return -1;
4733
 
                                        }
4734
 
                                        n = strlen(p);
4735
 
                                } else {
4736
 
                                        n = snprintf(buf, bufsize,
4737
 
                                                     ",M_TIME:%lu", m_time);
4738
 
                                }
4739
 
                        } else if (StrCaseCmp(name, "m_time") == 0) {
4740
 
                                if (determine_size) {
4741
 
                                        p = talloc_asprintf(ctx, "%lu", m_time);
4742
 
                                        if (!p) {
4743
 
                                                errno = ENOMEM;
4744
 
                                                return -1;
4745
 
                                        }
4746
 
                                        n = strlen(p);
4747
 
                                } else {
4748
 
                                        n = snprintf(buf, bufsize,
4749
 
                                                     "%lu", m_time);
4750
 
                                }
4751
 
                        }
4752
 
        
4753
 
                        if (!determine_size && n > bufsize) {
4754
 
                                errno = ERANGE;
4755
 
                                return -1;
4756
 
                        }
4757
 
                        buf += n;
4758
 
                        n_used += n;
4759
 
                        bufsize -= n;
4760
 
                }
4761
 
 
4762
 
                if (! exclude_dos_inode) {
4763
 
                        if (all || all_dos) {
4764
 
                                if (determine_size) {
4765
 
                                        p = talloc_asprintf(
4766
 
                                                ctx,
4767
 
                                                ",INODE:%.0f",
4768
 
                                                (double)ino);
4769
 
                                        if (!p) {
4770
 
                                                errno = ENOMEM;
4771
 
                                                return -1;
4772
 
                                        }
4773
 
                                        n = strlen(p);
4774
 
                                } else {
4775
 
                                        n = snprintf(buf, bufsize,
4776
 
                                                     ",INODE:%.0f",
4777
 
                                                     (double) ino);
4778
 
                                }
4779
 
                        } else if (StrCaseCmp(name, "inode") == 0) {
4780
 
                                if (determine_size) {
4781
 
                                        p = talloc_asprintf(
4782
 
                                                ctx,
4783
 
                                                "%.0f",
4784
 
                                                (double) ino);
4785
 
                                        if (!p) {
4786
 
                                                errno = ENOMEM;
4787
 
                                                return -1;
4788
 
                                        }
4789
 
                                        n = strlen(p);
4790
 
                                } else {
4791
 
                                        n = snprintf(buf, bufsize,
4792
 
                                                     "%.0f",
4793
 
                                                     (double) ino);
4794
 
                                }
4795
 
                        }
4796
 
        
4797
 
                        if (!determine_size && n > bufsize) {
4798
 
                                errno = ERANGE;
4799
 
                                return -1;
4800
 
                        }
4801
 
                        buf += n;
4802
 
                        n_used += n;
4803
 
                        bufsize -= n;
4804
 
                }
4805
 
 
4806
 
                /* Restore name pointer to its original value */
4807
 
                name -= 16;
4808
 
        }
4809
 
 
4810
 
        if (n_used == 0) {
4811
 
                errno = ENOATTR;
4812
 
                return -1;
4813
 
        }
4814
 
 
4815
 
        return n_used;
4816
 
}
4817
 
 
4818
 
 
4819
 
/***************************************************** 
4820
 
set the ACLs on a file given an ascii description
4821
 
*******************************************************/
4822
 
static int
4823
 
cacl_set(TALLOC_CTX *ctx,
4824
 
         struct cli_state *cli,
4825
 
         struct cli_state *ipc_cli,
4826
 
         POLICY_HND *pol,
4827
 
         const char *filename,
4828
 
         const char *the_acl,
4829
 
         int mode,
4830
 
         int flags)
4831
 
{
4832
 
        int fnum;
4833
 
        int err = 0;
4834
 
        SEC_DESC *sd = NULL, *old;
4835
 
        SEC_ACL *dacl = NULL;
4836
 
        DOM_SID *owner_sid = NULL; 
4837
 
        DOM_SID *grp_sid = NULL;
4838
 
        uint32 i, j;
4839
 
        size_t sd_size;
4840
 
        int ret = 0;
4841
 
        char *p;
4842
 
        BOOL numeric = True;
4843
 
 
4844
 
        /* the_acl will be null for REMOVE_ALL operations */
4845
 
        if (the_acl) {
4846
 
                numeric = ((p = strchr(the_acl, ':')) != NULL &&
4847
 
                           p > the_acl &&
4848
 
                           p[-1] != '+');
4849
 
 
4850
 
                /* if this is to set the entire ACL... */
4851
 
                if (*the_acl == '*') {
4852
 
                        /* ... then increment past the first colon */
4853
 
                        the_acl = p + 1;
4854
 
                }
4855
 
 
4856
 
                sd = sec_desc_parse(ctx, ipc_cli, pol, numeric,
4857
 
                                    CONST_DISCARD(char *, the_acl));
4858
 
 
4859
 
                if (!sd) {
4860
 
                        errno = EINVAL;
4861
 
                        return -1;
4862
 
                }
4863
 
        }
4864
 
 
4865
 
        /* SMBC_XATTR_MODE_REMOVE_ALL is the only caller
4866
 
           that doesn't deref sd */
4867
 
 
4868
 
        if (!sd && (mode != SMBC_XATTR_MODE_REMOVE_ALL)) {
4869
 
                errno = EINVAL;
4870
 
                return -1;
4871
 
        }
4872
 
 
4873
 
        /* The desired access below is the only one I could find that works
4874
 
           with NT4, W2KP and Samba */
4875
 
 
4876
 
        fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ);
4877
 
 
4878
 
        if (fnum == -1) {
4879
 
                DEBUG(5, ("cacl_set failed to open %s: %s\n",
4880
 
                          filename, cli_errstr(cli)));
4881
 
                errno = 0;
4882
 
                return -1;
4883
 
        }
4884
 
 
4885
 
        old = cli_query_secdesc(cli, fnum, ctx);
4886
 
 
4887
 
        if (!old) {
4888
 
                DEBUG(5, ("cacl_set Failed to query old descriptor\n"));
4889
 
                errno = 0;
4890
 
                return -1;
4891
 
        }
4892
 
 
4893
 
        cli_close(cli, fnum);
4894
 
 
4895
 
        switch (mode) {
4896
 
        case SMBC_XATTR_MODE_REMOVE_ALL:
4897
 
                old->dacl->num_aces = 0;
4898
 
                SAFE_FREE(old->dacl->ace);
4899
 
                SAFE_FREE(old->dacl);
4900
 
                old->off_dacl = 0;
4901
 
                dacl = old->dacl;
4902
 
                break;
4903
 
 
4904
 
        case SMBC_XATTR_MODE_REMOVE:
4905
 
                for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
4906
 
                        BOOL found = False;
4907
 
 
4908
 
                        for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
4909
 
                                if (sec_ace_equal(&sd->dacl->ace[i],
4910
 
                                                  &old->dacl->ace[j])) {
4911
 
                                        uint32 k;
4912
 
                                        for (k=j; k<old->dacl->num_aces-1;k++) {
4913
 
                                                old->dacl->ace[k] =
4914
 
                                                        old->dacl->ace[k+1];
4915
 
                                        }
4916
 
                                        old->dacl->num_aces--;
4917
 
                                        if (old->dacl->num_aces == 0) {
4918
 
                                                SAFE_FREE(old->dacl->ace);
4919
 
                                                SAFE_FREE(old->dacl);
4920
 
                                                old->off_dacl = 0;
4921
 
                                        }
4922
 
                                        found = True;
4923
 
                                        dacl = old->dacl;
4924
 
                                        break;
4925
 
                                }
4926
 
                        }
4927
 
 
4928
 
                        if (!found) {
4929
 
                                err = ENOATTR;
4930
 
                                ret = -1;
4931
 
                                goto failed;
4932
 
                        }
4933
 
                }
4934
 
                break;
4935
 
 
4936
 
        case SMBC_XATTR_MODE_ADD:
4937
 
                for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
4938
 
                        BOOL found = False;
4939
 
 
4940
 
                        for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
4941
 
                                if (sid_equal(&sd->dacl->ace[i].trustee,
4942
 
                                              &old->dacl->ace[j].trustee)) {
4943
 
                                        if (!(flags & SMBC_XATTR_FLAG_CREATE)) {
4944
 
                                                err = EEXIST;
4945
 
                                                ret = -1;
4946
 
                                                goto failed;
4947
 
                                        }
4948
 
                                        old->dacl->ace[j] = sd->dacl->ace[i];
4949
 
                                        ret = -1;
4950
 
                                        found = True;
4951
 
                                }
4952
 
                        }
4953
 
 
4954
 
                        if (!found && (flags & SMBC_XATTR_FLAG_REPLACE)) {
4955
 
                                err = ENOATTR;
4956
 
                                ret = -1;
4957
 
                                goto failed;
4958
 
                        }
4959
 
                        
4960
 
                        for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
4961
 
                                add_ace(&old->dacl, &sd->dacl->ace[i], ctx);
4962
 
                        }
4963
 
                }
4964
 
                dacl = old->dacl;
4965
 
                break;
4966
 
 
4967
 
        case SMBC_XATTR_MODE_SET:
4968
 
                old = sd;
4969
 
                owner_sid = old->owner_sid;
4970
 
                grp_sid = old->grp_sid;
4971
 
                dacl = old->dacl;
4972
 
                break;
4973
 
 
4974
 
        case SMBC_XATTR_MODE_CHOWN:
4975
 
                owner_sid = sd->owner_sid;
4976
 
                break;
4977
 
 
4978
 
        case SMBC_XATTR_MODE_CHGRP:
4979
 
                grp_sid = sd->grp_sid;
4980
 
                break;
4981
 
        }
4982
 
 
4983
 
        /* Denied ACE entries must come before allowed ones */
4984
 
        sort_acl(old->dacl);
4985
 
 
4986
 
        /* Create new security descriptor and set it */
4987
 
        sd = make_sec_desc(ctx, old->revision, SEC_DESC_SELF_RELATIVE, 
4988
 
                           owner_sid, grp_sid, NULL, dacl, &sd_size);
4989
 
 
4990
 
        fnum = cli_nt_create(cli, filename,
4991
 
                             WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS);
4992
 
 
4993
 
        if (fnum == -1) {
4994
 
                DEBUG(5, ("cacl_set failed to open %s: %s\n",
4995
 
                          filename, cli_errstr(cli)));
4996
 
                errno = 0;
4997
 
                return -1;
4998
 
        }
4999
 
 
5000
 
        if (!cli_set_secdesc(cli, fnum, sd)) {
5001
 
                DEBUG(5, ("ERROR: secdesc set failed: %s\n", cli_errstr(cli)));
5002
 
                ret = -1;
5003
 
        }
5004
 
 
5005
 
        /* Clean up */
5006
 
 
5007
 
 failed:
5008
 
        cli_close(cli, fnum);
5009
 
 
5010
 
        if (err != 0) {
5011
 
                errno = err;
5012
 
        }
5013
 
        
5014
 
        return ret;
5015
 
}
5016
 
 
5017
 
 
5018
 
static int
5019
 
smbc_setxattr_ctx(SMBCCTX *context,
5020
 
                  const char *fname,
5021
 
                  const char *name,
5022
 
                  const void *value,
5023
 
                  size_t size,
5024
 
                  int flags)
5025
 
{
5026
 
        int ret;
5027
 
        int ret2;
5028
 
        SMBCSRV *srv;
5029
 
        SMBCSRV *ipc_srv;
5030
 
        fstring server;
5031
 
        fstring share;
5032
 
        fstring user;
5033
 
        fstring password;
5034
 
        fstring workgroup;
5035
 
        pstring path;
5036
 
        TALLOC_CTX *ctx;
5037
 
        POLICY_HND pol;
5038
 
        DOS_ATTR_DESC *dad;
5039
 
 
5040
 
        if (!context || !context->internal ||
5041
 
            !context->internal->_initialized) {
5042
 
 
5043
 
                errno = EINVAL;  /* Best I can think of ... */
5044
 
                return -1;
5045
 
    
5046
 
        }
5047
 
 
5048
 
        if (!fname) {
5049
 
 
5050
 
                errno = EINVAL;
5051
 
                return -1;
5052
 
 
5053
 
        }
5054
 
  
5055
 
        DEBUG(4, ("smbc_setxattr(%s, %s, %.*s)\n",
5056
 
                  fname, name, (int) size, (const char*)value));
5057
 
 
5058
 
        if (smbc_parse_path(context, fname,
5059
 
                            workgroup, sizeof(workgroup),
5060
 
                            server, sizeof(server),
5061
 
                            share, sizeof(share),
5062
 
                            path, sizeof(path),
5063
 
                            user, sizeof(user),
5064
 
                            password, sizeof(password),
5065
 
                            NULL, 0)) {
5066
 
                errno = EINVAL;
5067
 
                return -1;
5068
 
        }
5069
 
 
5070
 
        if (user[0] == (char)0) fstrcpy(user, context->user);
5071
 
 
5072
 
        srv = smbc_server(context, True,
5073
 
                          server, share, workgroup, user, password);
5074
 
        if (!srv) {
5075
 
                return -1;  /* errno set by smbc_server */
5076
 
        }
5077
 
 
5078
 
        if (! srv->no_nt_session) {
5079
 
                ipc_srv = smbc_attr_server(context, server, share,
5080
 
                                           workgroup, user, password,
5081
 
                                           &pol);
5082
 
                srv->no_nt_session = True;
5083
 
        } else {
5084
 
                ipc_srv = NULL;
5085
 
        }
5086
 
        
5087
 
        ctx = talloc_init("smbc_setxattr");
5088
 
        if (!ctx) {
5089
 
                errno = ENOMEM;
5090
 
                return -1;
5091
 
        }
5092
 
 
5093
 
        /*
5094
 
         * Are they asking to set the entire set of known attributes?
5095
 
         */
5096
 
        if (StrCaseCmp(name, "system.*") == 0 ||
5097
 
            StrCaseCmp(name, "system.*+") == 0) {
5098
 
                /* Yup. */
5099
 
                char *namevalue =
5100
 
                        talloc_asprintf(ctx, "%s:%s",
5101
 
                                        name+7, (const char *) value);
5102
 
                if (! namevalue) {
5103
 
                        errno = ENOMEM;
5104
 
                        ret = -1;
5105
 
                        return -1;
5106
 
                }
5107
 
 
5108
 
                if (ipc_srv) {
5109
 
                        ret = cacl_set(ctx, srv->cli,
5110
 
                                       ipc_srv->cli, &pol, path,
5111
 
                                       namevalue,
5112
 
                                       (*namevalue == '*'
5113
 
                                        ? SMBC_XATTR_MODE_SET
5114
 
                                        : SMBC_XATTR_MODE_ADD),
5115
 
                                       flags);
5116
 
                } else {
5117
 
                        ret = 0;
5118
 
                }
5119
 
 
5120
 
                /* get a DOS Attribute Descriptor with current attributes */
5121
 
                dad = dos_attr_query(context, ctx, path, srv);
5122
 
                if (dad) {
5123
 
                        /* Overwrite old with new, using what was provided */
5124
 
                        dos_attr_parse(context, dad, srv, namevalue);
5125
 
 
5126
 
                        /* Set the new DOS attributes */
5127
 
                        if (! smbc_setatr(context, srv, path,
5128
 
                                          dad->c_time,
5129
 
                                          dad->a_time,
5130
 
                                          dad->m_time,
5131
 
                                          dad->mode)) {
5132
 
 
5133
 
                                /* cause failure if NT failed too */
5134
 
                                dad = NULL; 
5135
 
                        }
5136
 
                }
5137
 
 
5138
 
                /* we only fail if both NT and DOS sets failed */
5139
 
                if (ret < 0 && ! dad) {
5140
 
                        ret = -1; /* in case dad was null */
5141
 
                }
5142
 
                else {
5143
 
                        ret = 0;
5144
 
                }
5145
 
 
5146
 
                talloc_destroy(ctx);
5147
 
                return ret;
5148
 
        }
5149
 
 
5150
 
        /*
5151
 
         * Are they asking to set an access control element or to set
5152
 
         * the entire access control list?
5153
 
         */
5154
 
        if (StrCaseCmp(name, "system.nt_sec_desc.*") == 0 ||
5155
 
            StrCaseCmp(name, "system.nt_sec_desc.*+") == 0 ||
5156
 
            StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 ||
5157
 
            StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 ||
5158
 
            StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) {
5159
 
 
5160
 
                /* Yup. */
5161
 
                char *namevalue =
5162
 
                        talloc_asprintf(ctx, "%s:%s",
5163
 
                                        name+19, (const char *) value);
5164
 
 
5165
 
                if (! ipc_srv) {
5166
 
                        ret = -1; /* errno set by smbc_server() */
5167
 
                }
5168
 
                else if (! namevalue) {
5169
 
                        errno = ENOMEM;
5170
 
                        ret = -1;
5171
 
                } else {
5172
 
                        ret = cacl_set(ctx, srv->cli,
5173
 
                                       ipc_srv->cli, &pol, path,
5174
 
                                       namevalue,
5175
 
                                       (*namevalue == '*'
5176
 
                                        ? SMBC_XATTR_MODE_SET
5177
 
                                        : SMBC_XATTR_MODE_ADD),
5178
 
                                       flags);
5179
 
                }
5180
 
                talloc_destroy(ctx);
5181
 
                return ret;
5182
 
        }
5183
 
 
5184
 
        /*
5185
 
         * Are they asking to set the owner?
5186
 
         */
5187
 
        if (StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 ||
5188
 
            StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0) {
5189
 
 
5190
 
                /* Yup. */
5191
 
                char *namevalue =
5192
 
                        talloc_asprintf(ctx, "%s:%s",
5193
 
                                        name+19, (const char *) value);
5194
 
 
5195
 
                if (! ipc_srv) {
5196
 
                        
5197
 
                        ret = -1; /* errno set by smbc_server() */
5198
 
                }
5199
 
                else if (! namevalue) {
5200
 
                        errno = ENOMEM;
5201
 
                        ret = -1;
5202
 
                } else {
5203
 
                        ret = cacl_set(ctx, srv->cli,
5204
 
                                       ipc_srv->cli, &pol, path,
5205
 
                                       namevalue, SMBC_XATTR_MODE_CHOWN, 0);
5206
 
                }
5207
 
                talloc_destroy(ctx);
5208
 
                return ret;
5209
 
        }
5210
 
 
5211
 
        /*
5212
 
         * Are they asking to set the group?
5213
 
         */
5214
 
        if (StrCaseCmp(name, "system.nt_sec_desc.group") == 0 ||
5215
 
            StrCaseCmp(name, "system.nt_sec_desc.group+") == 0) {
5216
 
 
5217
 
                /* Yup. */
5218
 
                char *namevalue =
5219
 
                        talloc_asprintf(ctx, "%s:%s",
5220
 
                                        name+19, (const char *) value);
5221
 
 
5222
 
                if (! ipc_srv) {
5223
 
                        /* errno set by smbc_server() */
5224
 
                        ret = -1;
5225
 
                }
5226
 
                else if (! namevalue) {
5227
 
                        errno = ENOMEM;
5228
 
                        ret = -1;
5229
 
                } else {
5230
 
                        ret = cacl_set(ctx, srv->cli,
5231
 
                                       ipc_srv->cli, &pol, path,
5232
 
                                       namevalue, SMBC_XATTR_MODE_CHOWN, 0);
5233
 
                }
5234
 
                talloc_destroy(ctx);
5235
 
                return ret;
5236
 
        }
5237
 
 
5238
 
        /*
5239
 
         * Are they asking to set a DOS attribute?
5240
 
         */
5241
 
        if (StrCaseCmp(name, "system.dos_attr.*") == 0 ||
5242
 
            StrCaseCmp(name, "system.dos_attr.mode") == 0 ||
5243
 
            StrCaseCmp(name, "system.dos_attr.c_time") == 0 ||
5244
 
            StrCaseCmp(name, "system.dos_attr.a_time") == 0 ||
5245
 
            StrCaseCmp(name, "system.dos_attr.m_time") == 0) {
5246
 
 
5247
 
                /* get a DOS Attribute Descriptor with current attributes */
5248
 
                dad = dos_attr_query(context, ctx, path, srv);
5249
 
                if (dad) {
5250
 
                        char *namevalue =
5251
 
                                talloc_asprintf(ctx, "%s:%s",
5252
 
                                                name+16, (const char *) value);
5253
 
                        if (! namevalue) {
5254
 
                                errno = ENOMEM;
5255
 
                                ret = -1;
5256
 
                        } else {
5257
 
                                /* Overwrite old with provided new params */
5258
 
                                dos_attr_parse(context, dad, srv, namevalue);
5259
 
 
5260
 
                                /* Set the new DOS attributes */
5261
 
                                ret2 = smbc_setatr(context, srv, path,
5262
 
                                                   dad->c_time,
5263
 
                                                   dad->a_time,
5264
 
                                                   dad->m_time,
5265
 
                                                   dad->mode);
5266
 
 
5267
 
                                /* ret2 has True (success) / False (failure) */
5268
 
                                if (ret2) {
5269
 
                                        ret = 0;
5270
 
                                } else {
5271
 
                                        ret = -1;
5272
 
                                }
5273
 
                        }
5274
 
                } else {
5275
 
                        ret = -1;
5276
 
                }
5277
 
 
5278
 
                talloc_destroy(ctx);
5279
 
                return ret;
5280
 
        }
5281
 
 
5282
 
        /* Unsupported attribute name */
5283
 
        talloc_destroy(ctx);
5284
 
        errno = EINVAL;
5285
 
        return -1;
5286
 
}
5287
 
 
5288
 
static int
5289
 
smbc_getxattr_ctx(SMBCCTX *context,
5290
 
                  const char *fname,
5291
 
                  const char *name,
5292
 
                  const void *value,
5293
 
                  size_t size)
5294
 
{
5295
 
        int ret;
5296
 
        SMBCSRV *srv;
5297
 
        SMBCSRV *ipc_srv;
5298
 
        fstring server;
5299
 
        fstring share;
5300
 
        fstring user;
5301
 
        fstring password;
5302
 
        fstring workgroup;
5303
 
        pstring path;
5304
 
        TALLOC_CTX *ctx;
5305
 
        POLICY_HND pol;
5306
 
 
5307
 
 
5308
 
        if (!context || !context->internal ||
5309
 
            !context->internal->_initialized) {
5310
 
 
5311
 
                errno = EINVAL;  /* Best I can think of ... */
5312
 
                return -1;
5313
 
    
5314
 
        }
5315
 
 
5316
 
        if (!fname) {
5317
 
 
5318
 
                errno = EINVAL;
5319
 
                return -1;
5320
 
 
5321
 
        }
5322
 
  
5323
 
        DEBUG(4, ("smbc_getxattr(%s, %s)\n", fname, name));
5324
 
 
5325
 
        if (smbc_parse_path(context, fname,
5326
 
                            workgroup, sizeof(workgroup),
5327
 
                            server, sizeof(server),
5328
 
                            share, sizeof(share),
5329
 
                            path, sizeof(path),
5330
 
                            user, sizeof(user),
5331
 
                            password, sizeof(password),
5332
 
                            NULL, 0)) {
5333
 
                errno = EINVAL;
5334
 
                return -1;
5335
 
        }
5336
 
 
5337
 
        if (user[0] == (char)0) fstrcpy(user, context->user);
5338
 
 
5339
 
        srv = smbc_server(context, True,
5340
 
                          server, share, workgroup, user, password);
5341
 
        if (!srv) {
5342
 
                return -1;  /* errno set by smbc_server */
5343
 
        }
5344
 
 
5345
 
        if (! srv->no_nt_session) {
5346
 
                ipc_srv = smbc_attr_server(context, server, share,
5347
 
                                           workgroup, user, password,
5348
 
                                           &pol);
5349
 
                if (! ipc_srv) {
5350
 
                        srv->no_nt_session = True;
5351
 
                }
5352
 
        } else {
5353
 
                ipc_srv = NULL;
5354
 
        }
5355
 
        
5356
 
        ctx = talloc_init("smbc:getxattr");
5357
 
        if (!ctx) {
5358
 
                errno = ENOMEM;
5359
 
                return -1;
5360
 
        }
5361
 
 
5362
 
        /* Are they requesting a supported attribute? */
5363
 
        if (StrCaseCmp(name, "system.*") == 0 ||
5364
 
            StrnCaseCmp(name, "system.*!", 9) == 0 ||
5365
 
            StrCaseCmp(name, "system.*+") == 0 ||
5366
 
            StrnCaseCmp(name, "system.*+!", 10) == 0 ||
5367
 
            StrCaseCmp(name, "system.nt_sec_desc.*") == 0 ||
5368
 
            StrnCaseCmp(name, "system.nt_sec_desc.*!", 21) == 0 ||
5369
 
            StrCaseCmp(name, "system.nt_sec_desc.*+") == 0 ||
5370
 
            StrnCaseCmp(name, "system.nt_sec_desc.*+!", 22) == 0 ||
5371
 
            StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 ||
5372
 
            StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 ||
5373
 
            StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0 ||
5374
 
            StrCaseCmp(name, "system.nt_sec_desc.group") == 0 ||
5375
 
            StrCaseCmp(name, "system.nt_sec_desc.group+") == 0 ||
5376
 
            StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 ||
5377
 
            StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0 ||
5378
 
            StrCaseCmp(name, "system.dos_attr.*") == 0 ||
5379
 
            StrnCaseCmp(name, "system.dos_attr.*!", 18) == 0 ||
5380
 
            StrCaseCmp(name, "system.dos_attr.mode") == 0 ||
5381
 
            StrCaseCmp(name, "system.dos_attr.size") == 0 ||
5382
 
            StrCaseCmp(name, "system.dos_attr.c_time") == 0 ||
5383
 
            StrCaseCmp(name, "system.dos_attr.a_time") == 0 ||
5384
 
            StrCaseCmp(name, "system.dos_attr.m_time") == 0 ||
5385
 
            StrCaseCmp(name, "system.dos_attr.inode") == 0) {
5386
 
 
5387
 
                /* Yup. */
5388
 
                ret = cacl_get(context, ctx, srv,
5389
 
                               ipc_srv == NULL ? NULL : ipc_srv->cli, 
5390
 
                               &pol, path,
5391
 
                               CONST_DISCARD(char *, name),
5392
 
                               CONST_DISCARD(char *, value), size);
5393
 
                if (ret < 0 && errno == 0) {
5394
 
                        errno = smbc_errno(context, srv->cli);
5395
 
                }
5396
 
                talloc_destroy(ctx);
5397
 
                return ret;
5398
 
        }
5399
 
 
5400
 
        /* Unsupported attribute name */
5401
 
        talloc_destroy(ctx);
5402
 
        errno = EINVAL;
5403
 
        return -1;
5404
 
}
5405
 
 
5406
 
 
5407
 
static int
5408
 
smbc_removexattr_ctx(SMBCCTX *context,
5409
 
                     const char *fname,
5410
 
                     const char *name)
5411
 
{
5412
 
        int ret;
5413
 
        SMBCSRV *srv;
5414
 
        SMBCSRV *ipc_srv;
5415
 
        fstring server;
5416
 
        fstring share;
5417
 
        fstring user;
5418
 
        fstring password;
5419
 
        fstring workgroup;
5420
 
        pstring path;
5421
 
        TALLOC_CTX *ctx;
5422
 
        POLICY_HND pol;
5423
 
 
5424
 
        if (!context || !context->internal ||
5425
 
            !context->internal->_initialized) {
5426
 
 
5427
 
                errno = EINVAL;  /* Best I can think of ... */
5428
 
                return -1;
5429
 
    
5430
 
        }
5431
 
 
5432
 
        if (!fname) {
5433
 
 
5434
 
                errno = EINVAL;
5435
 
                return -1;
5436
 
 
5437
 
        }
5438
 
  
5439
 
        DEBUG(4, ("smbc_removexattr(%s, %s)\n", fname, name));
5440
 
 
5441
 
        if (smbc_parse_path(context, fname,
5442
 
                            workgroup, sizeof(workgroup),
5443
 
                            server, sizeof(server),
5444
 
                            share, sizeof(share),
5445
 
                            path, sizeof(path),
5446
 
                            user, sizeof(user),
5447
 
                            password, sizeof(password),
5448
 
                            NULL, 0)) {
5449
 
                errno = EINVAL;
5450
 
                return -1;
5451
 
        }
5452
 
 
5453
 
        if (user[0] == (char)0) fstrcpy(user, context->user);
5454
 
 
5455
 
        srv = smbc_server(context, True,
5456
 
                          server, share, workgroup, user, password);
5457
 
        if (!srv) {
5458
 
                return -1;  /* errno set by smbc_server */
5459
 
        }
5460
 
 
5461
 
        if (! srv->no_nt_session) {
5462
 
                ipc_srv = smbc_attr_server(context, server, share,
5463
 
                                           workgroup, user, password,
5464
 
                                           &pol);
5465
 
                srv->no_nt_session = True;
5466
 
        } else {
5467
 
                ipc_srv = NULL;
5468
 
        }
5469
 
        
5470
 
        if (! ipc_srv) {
5471
 
                return -1; /* errno set by smbc_attr_server */
5472
 
        }
5473
 
 
5474
 
        ctx = talloc_init("smbc_removexattr");
5475
 
        if (!ctx) {
5476
 
                errno = ENOMEM;
5477
 
                return -1;
5478
 
        }
5479
 
 
5480
 
        /* Are they asking to set the entire ACL? */
5481
 
        if (StrCaseCmp(name, "system.nt_sec_desc.*") == 0 ||
5482
 
            StrCaseCmp(name, "system.nt_sec_desc.*+") == 0) {
5483
 
 
5484
 
                /* Yup. */
5485
 
                ret = cacl_set(ctx, srv->cli,
5486
 
                               ipc_srv->cli, &pol, path,
5487
 
                               NULL, SMBC_XATTR_MODE_REMOVE_ALL, 0);
5488
 
                talloc_destroy(ctx);
5489
 
                return ret;
5490
 
        }
5491
 
 
5492
 
        /*
5493
 
         * Are they asking to remove one or more spceific security descriptor
5494
 
         * attributes?
5495
 
         */
5496
 
        if (StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 ||
5497
 
            StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 ||
5498
 
            StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0 ||
5499
 
            StrCaseCmp(name, "system.nt_sec_desc.group") == 0 ||
5500
 
            StrCaseCmp(name, "system.nt_sec_desc.group+") == 0 ||
5501
 
            StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 ||
5502
 
            StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) {
5503
 
 
5504
 
                /* Yup. */
5505
 
                ret = cacl_set(ctx, srv->cli,
5506
 
                               ipc_srv->cli, &pol, path,
5507
 
                               name + 19, SMBC_XATTR_MODE_REMOVE, 0);
5508
 
                talloc_destroy(ctx);
5509
 
                return ret;
5510
 
        }
5511
 
 
5512
 
        /* Unsupported attribute name */
5513
 
        talloc_destroy(ctx);
5514
 
        errno = EINVAL;
5515
 
        return -1;
5516
 
}
5517
 
 
5518
 
static int
5519
 
smbc_listxattr_ctx(SMBCCTX *context,
5520
 
                   const char *fname,
5521
 
                   char *list,
5522
 
                   size_t size)
5523
 
{
5524
 
        /*
5525
 
         * This isn't quite what listxattr() is supposed to do.  This returns
5526
 
         * the complete set of attribute names, always, rather than only those
5527
 
         * attribute names which actually exist for a file.  Hmmm...
5528
 
         */
5529
 
        const char supported[] =
5530
 
                "system.*\0"
5531
 
                "system.*+\0"
5532
 
                "system.nt_sec_desc.revision\0"
5533
 
                "system.nt_sec_desc.owner\0"
5534
 
                "system.nt_sec_desc.owner+\0"
5535
 
                "system.nt_sec_desc.group\0"
5536
 
                "system.nt_sec_desc.group+\0"
5537
 
                "system.nt_sec_desc.acl.*\0"
5538
 
                "system.nt_sec_desc.acl\0"
5539
 
                "system.nt_sec_desc.acl+\0"
5540
 
                "system.nt_sec_desc.*\0"
5541
 
                "system.nt_sec_desc.*+\0"
5542
 
                "system.dos_attr.*\0"
5543
 
                "system.dos_attr.mode\0"
5544
 
                "system.dos_attr.c_time\0"
5545
 
                "system.dos_attr.a_time\0"
5546
 
                "system.dos_attr.m_time\0"
5547
 
                ;
5548
 
 
5549
 
        if (size == 0) {
5550
 
                return sizeof(supported);
5551
 
        }
5552
 
 
5553
 
        if (sizeof(supported) > size) {
5554
 
                errno = ERANGE;
5555
 
                return -1;
5556
 
        }
5557
 
 
5558
 
        /* this can't be strcpy() because there are embedded null characters */
5559
 
        memcpy(list, supported, sizeof(supported));
5560
 
        return sizeof(supported);
5561
 
}
5562
 
 
5563
 
 
5564
 
/*
5565
 
 * Open a print file to be written to by other calls
5566
 
 */
5567
 
 
5568
 
static SMBCFILE *
5569
 
smbc_open_print_job_ctx(SMBCCTX *context,
5570
 
                        const char *fname)
5571
 
{
5572
 
        fstring server;
5573
 
        fstring share;
5574
 
        fstring user;
5575
 
        fstring password;
5576
 
        pstring path;
5577
 
        
5578
 
        if (!context || !context->internal ||
5579
 
            !context->internal->_initialized) {
5580
 
 
5581
 
                errno = EINVAL;
5582
 
                return NULL;
5583
 
    
5584
 
        }
5585
 
 
5586
 
        if (!fname) {
5587
 
 
5588
 
                errno = EINVAL;
5589
 
                return NULL;
5590
 
 
5591
 
        }
5592
 
  
5593
 
        DEBUG(4, ("smbc_open_print_job_ctx(%s)\n", fname));
5594
 
 
5595
 
        if (smbc_parse_path(context, fname,
5596
 
                            NULL, 0,
5597
 
                            server, sizeof(server),
5598
 
                            share, sizeof(share),
5599
 
                            path, sizeof(path),
5600
 
                            user, sizeof(user),
5601
 
                            password, sizeof(password),
5602
 
                            NULL, 0)) {
5603
 
                errno = EINVAL;
5604
 
                return NULL;
5605
 
        }
5606
 
 
5607
 
        /* What if the path is empty, or the file exists? */
5608
 
 
5609
 
        return context->open(context, fname, O_WRONLY, 666);
5610
 
 
5611
 
}
5612
 
 
5613
 
/*
5614
 
 * Routine to print a file on a remote server ...
5615
 
 *
5616
 
 * We open the file, which we assume to be on a remote server, and then
5617
 
 * copy it to a print file on the share specified by printq.
5618
 
 */
5619
 
 
5620
 
static int
5621
 
smbc_print_file_ctx(SMBCCTX *c_file,
5622
 
                    const char *fname,
5623
 
                    SMBCCTX *c_print,
5624
 
                    const char *printq)
5625
 
{
5626
 
        SMBCFILE *fid1;
5627
 
        SMBCFILE *fid2;
5628
 
        int bytes;
5629
 
        int saverr;
5630
 
        int tot_bytes = 0;
5631
 
        char buf[4096];
5632
 
 
5633
 
        if (!c_file || !c_file->internal->_initialized || !c_print ||
5634
 
            !c_print->internal->_initialized) {
5635
 
 
5636
 
                errno = EINVAL;
5637
 
                return -1;
5638
 
 
5639
 
        }
5640
 
 
5641
 
        if (!fname && !printq) {
5642
 
 
5643
 
                errno = EINVAL;
5644
 
                return -1;
5645
 
 
5646
 
        }
5647
 
 
5648
 
        /* Try to open the file for reading ... */
5649
 
 
5650
 
        if ((long)(fid1 = c_file->open(c_file, fname, O_RDONLY, 0666)) < 0) {
5651
 
                
5652
 
                DEBUG(3, ("Error, fname=%s, errno=%i\n", fname, errno));
5653
 
                return -1;  /* smbc_open sets errno */
5654
 
                
5655
 
        }
5656
 
 
5657
 
        /* Now, try to open the printer file for writing */
5658
 
 
5659
 
        if ((long)(fid2 = c_print->open_print_job(c_print, printq)) < 0) {
5660
 
 
5661
 
                saverr = errno;  /* Save errno */
5662
 
                c_file->close_fn(c_file, fid1);
5663
 
                errno = saverr;
5664
 
                return -1;
5665
 
 
5666
 
        }
5667
 
 
5668
 
        while ((bytes = c_file->read(c_file, fid1, buf, sizeof(buf))) > 0) {
5669
 
 
5670
 
                tot_bytes += bytes;
5671
 
 
5672
 
                if ((c_print->write(c_print, fid2, buf, bytes)) < 0) {
5673
 
 
5674
 
                        saverr = errno;
5675
 
                        c_file->close_fn(c_file, fid1);
5676
 
                        c_print->close_fn(c_print, fid2);
5677
 
                        errno = saverr;
5678
 
 
5679
 
                }
5680
 
 
5681
 
        }
5682
 
 
5683
 
        saverr = errno;
5684
 
 
5685
 
        c_file->close_fn(c_file, fid1);  /* We have to close these anyway */
5686
 
        c_print->close_fn(c_print, fid2);
5687
 
 
5688
 
        if (bytes < 0) {
5689
 
 
5690
 
                errno = saverr;
5691
 
                return -1;
5692
 
 
5693
 
        }
5694
 
 
5695
 
        return tot_bytes;
5696
 
 
5697
 
}
5698
 
 
5699
 
/*
5700
 
 * Routine to list print jobs on a printer share ...
5701
 
 */
5702
 
 
5703
 
static int
5704
 
smbc_list_print_jobs_ctx(SMBCCTX *context,
5705
 
                         const char *fname,
5706
 
                         smbc_list_print_job_fn fn)
5707
 
{
5708
 
        SMBCSRV *srv;
5709
 
        fstring server;
5710
 
        fstring share;
5711
 
        fstring user;
5712
 
        fstring password;
5713
 
        fstring workgroup;
5714
 
        pstring path;
5715
 
 
5716
 
        if (!context || !context->internal ||
5717
 
            !context->internal->_initialized) {
5718
 
 
5719
 
                errno = EINVAL;
5720
 
                return -1;
5721
 
 
5722
 
        }
5723
 
 
5724
 
        if (!fname) {
5725
 
                
5726
 
                errno = EINVAL;
5727
 
                return -1;
5728
 
 
5729
 
        }
5730
 
  
5731
 
        DEBUG(4, ("smbc_list_print_jobs(%s)\n", fname));
5732
 
 
5733
 
        if (smbc_parse_path(context, fname,
5734
 
                            workgroup, sizeof(workgroup),
5735
 
                            server, sizeof(server),
5736
 
                            share, sizeof(share),
5737
 
                            path, sizeof(path),
5738
 
                            user, sizeof(user),
5739
 
                            password, sizeof(password),
5740
 
                            NULL, 0)) {
5741
 
                errno = EINVAL;
5742
 
                return -1;
5743
 
        }
5744
 
 
5745
 
        if (user[0] == (char)0) fstrcpy(user, context->user);
5746
 
        
5747
 
        srv = smbc_server(context, True,
5748
 
                          server, share, workgroup, user, password);
5749
 
 
5750
 
        if (!srv) {
5751
 
 
5752
 
                return -1;  /* errno set by smbc_server */
5753
 
 
5754
 
        }
5755
 
 
5756
 
        if (cli_print_queue(srv->cli,
5757
 
                            (void (*)(struct print_job_info *))fn) < 0) {
5758
 
 
5759
 
                errno = smbc_errno(context, srv->cli);
5760
 
                return -1;
5761
 
 
5762
 
        }
5763
 
        
5764
 
        return 0;
5765
 
 
5766
 
}
5767
 
 
5768
 
/*
5769
 
 * Delete a print job from a remote printer share
5770
 
 */
5771
 
 
5772
 
static int
5773
 
smbc_unlink_print_job_ctx(SMBCCTX *context,
5774
 
                          const char *fname,
5775
 
                          int id)
5776
 
{
5777
 
        SMBCSRV *srv;
5778
 
        fstring server;
5779
 
        fstring share;
5780
 
        fstring user;
5781
 
        fstring password;
5782
 
        fstring workgroup;
5783
 
        pstring path;
5784
 
        int err;
5785
 
 
5786
 
        if (!context || !context->internal ||
5787
 
            !context->internal->_initialized) {
5788
 
 
5789
 
                errno = EINVAL;
5790
 
                return -1;
5791
 
 
5792
 
        }
5793
 
 
5794
 
        if (!fname) {
5795
 
 
5796
 
                errno = EINVAL;
5797
 
                return -1;
5798
 
 
5799
 
        }
5800
 
  
5801
 
        DEBUG(4, ("smbc_unlink_print_job(%s)\n", fname));
5802
 
 
5803
 
        if (smbc_parse_path(context, fname,
5804
 
                            workgroup, sizeof(workgroup),
5805
 
                            server, sizeof(server),
5806
 
                            share, sizeof(share),
5807
 
                            path, sizeof(path),
5808
 
                            user, sizeof(user),
5809
 
                            password, sizeof(password),
5810
 
                            NULL, 0)) {
5811
 
                errno = EINVAL;
5812
 
                return -1;
5813
 
        }
5814
 
 
5815
 
        if (user[0] == (char)0) fstrcpy(user, context->user);
5816
 
 
5817
 
        srv = smbc_server(context, True,
5818
 
                          server, share, workgroup, user, password);
5819
 
 
5820
 
        if (!srv) {
5821
 
 
5822
 
                return -1;  /* errno set by smbc_server */
5823
 
 
5824
 
        }
5825
 
 
5826
 
        if ((err = cli_printjob_del(srv->cli, id)) != 0) {
5827
 
 
5828
 
                if (err < 0)
5829
 
                        errno = smbc_errno(context, srv->cli);
5830
 
                else if (err == ERRnosuchprintjob)
5831
 
                        errno = EINVAL;
5832
 
                return -1;
5833
 
 
5834
 
        }
5835
 
 
5836
 
        return 0;
5837
 
 
5838
 
}
5839
 
 
5840
 
/*
5841
 
 * Get a new empty handle to fill in with your own info 
5842
 
 */
5843
 
SMBCCTX *
5844
 
smbc_new_context(void)
5845
 
{
5846
 
        SMBCCTX *context;
5847
 
 
5848
 
        context = SMB_MALLOC_P(SMBCCTX);
5849
 
        if (!context) {
5850
 
                errno = ENOMEM;
5851
 
                return NULL;
5852
 
        }
5853
 
 
5854
 
        ZERO_STRUCTP(context);
5855
 
 
5856
 
        context->internal = SMB_MALLOC_P(struct smbc_internal_data);
5857
 
        if (!context->internal) {
5858
 
                SAFE_FREE(context);
5859
 
                errno = ENOMEM;
5860
 
                return NULL;
5861
 
        }
5862
 
 
5863
 
        ZERO_STRUCTP(context->internal);
5864
 
 
5865
 
        
5866
 
        /* ADD REASONABLE DEFAULTS */
5867
 
        context->debug            = 0;
5868
 
        context->timeout          = 20000; /* 20 seconds */
5869
 
 
5870
 
        context->options.browse_max_lmb_count      = 3;    /* # LMBs to query */
5871
 
        context->options.urlencode_readdir_entries = False;/* backward compat */
5872
 
        context->options.one_share_per_server      = False;/* backward compat */
5873
 
 
5874
 
        context->open                              = smbc_open_ctx;
5875
 
        context->creat                             = smbc_creat_ctx;
5876
 
        context->read                              = smbc_read_ctx;
5877
 
        context->write                             = smbc_write_ctx;
5878
 
        context->close_fn                          = smbc_close_ctx;
5879
 
        context->unlink                            = smbc_unlink_ctx;
5880
 
        context->rename                            = smbc_rename_ctx;
5881
 
        context->lseek                             = smbc_lseek_ctx;
5882
 
        context->stat                              = smbc_stat_ctx;
5883
 
        context->fstat                             = smbc_fstat_ctx;
5884
 
        context->opendir                           = smbc_opendir_ctx;
5885
 
        context->closedir                          = smbc_closedir_ctx;
5886
 
        context->readdir                           = smbc_readdir_ctx;
5887
 
        context->getdents                          = smbc_getdents_ctx;
5888
 
        context->mkdir                             = smbc_mkdir_ctx;
5889
 
        context->rmdir                             = smbc_rmdir_ctx;
5890
 
        context->telldir                           = smbc_telldir_ctx;
5891
 
        context->lseekdir                          = smbc_lseekdir_ctx;
5892
 
        context->fstatdir                          = smbc_fstatdir_ctx;
5893
 
        context->chmod                             = smbc_chmod_ctx;
5894
 
        context->utimes                            = smbc_utimes_ctx;
5895
 
        context->setxattr                          = smbc_setxattr_ctx;
5896
 
        context->getxattr                          = smbc_getxattr_ctx;
5897
 
        context->removexattr                       = smbc_removexattr_ctx;
5898
 
        context->listxattr                         = smbc_listxattr_ctx;
5899
 
        context->open_print_job                    = smbc_open_print_job_ctx;
5900
 
        context->print_file                        = smbc_print_file_ctx;
5901
 
        context->list_print_jobs                   = smbc_list_print_jobs_ctx;
5902
 
        context->unlink_print_job                  = smbc_unlink_print_job_ctx;
5903
 
 
5904
 
        context->callbacks.check_server_fn         = smbc_check_server;
5905
 
        context->callbacks.remove_unused_server_fn = smbc_remove_unused_server;
5906
 
 
5907
 
        smbc_default_cache_functions(context);
5908
 
 
5909
 
        return context;
5910
 
}
5911
 
 
5912
 
/* 
5913
 
 * Free a context
5914
 
 *
5915
 
 * Returns 0 on success. Otherwise returns 1, the SMBCCTX is _not_ freed 
5916
 
 * and thus you'll be leaking memory if not handled properly.
5917
 
 *
5918
 
 */
5919
 
int
5920
 
smbc_free_context(SMBCCTX *context,
5921
 
                  int shutdown_ctx)
5922
 
{
5923
 
        if (!context) {
5924
 
                errno = EBADF;
5925
 
                return 1;
5926
 
        }
5927
 
        
5928
 
        if (shutdown_ctx) {
5929
 
                SMBCFILE * f;
5930
 
                DEBUG(1,("Performing aggressive shutdown.\n"));
5931
 
                
5932
 
                f = context->internal->_files;
5933
 
                while (f) {
5934
 
                        context->close_fn(context, f);
5935
 
                        f = f->next;
5936
 
                }
5937
 
                context->internal->_files = NULL;
5938
 
 
5939
 
                /* First try to remove the servers the nice way. */
5940
 
                if (context->callbacks.purge_cached_fn(context)) {
5941
 
                        SMBCSRV * s;
5942
 
                        SMBCSRV * next;
5943
 
                        DEBUG(1, ("Could not purge all servers, "
5944
 
                                  "Nice way shutdown failed.\n"));
5945
 
                        s = context->internal->_servers;
5946
 
                        while (s) {
5947
 
                                DEBUG(1, ("Forced shutdown: %p (fd=%d)\n",
5948
 
                                          s, s->cli->fd));
5949
 
                                cli_shutdown(s->cli);
5950
 
                                context->callbacks.remove_cached_srv_fn(context,
5951
 
                                                                        s);
5952
 
                                next = s->next;
5953
 
                                DLIST_REMOVE(context->internal->_servers, s);
5954
 
                                SAFE_FREE(s);
5955
 
                                s = next;
5956
 
                        }
5957
 
                        context->internal->_servers = NULL;
5958
 
                }
5959
 
        }
5960
 
        else {
5961
 
                /* This is the polite way */    
5962
 
                if (context->callbacks.purge_cached_fn(context)) {
5963
 
                        DEBUG(1, ("Could not purge all servers, "
5964
 
                                  "free_context failed.\n"));
5965
 
                        errno = EBUSY;
5966
 
                        return 1;
5967
 
                }
5968
 
                if (context->internal->_servers) {
5969
 
                        DEBUG(1, ("Active servers in context, "
5970
 
                                  "free_context failed.\n"));
5971
 
                        errno = EBUSY;
5972
 
                        return 1;
5973
 
                }
5974
 
                if (context->internal->_files) {
5975
 
                        DEBUG(1, ("Active files in context, "
5976
 
                                  "free_context failed.\n"));
5977
 
                        errno = EBUSY;
5978
 
                        return 1;
5979
 
                }               
5980
 
        }
5981
 
 
5982
 
        /* Things we have to clean up */
5983
 
        SAFE_FREE(context->workgroup);
5984
 
        SAFE_FREE(context->netbios_name);
5985
 
        SAFE_FREE(context->user);
5986
 
        
5987
 
        DEBUG(3, ("Context %p succesfully freed\n", context));
5988
 
        SAFE_FREE(context->internal);
5989
 
        SAFE_FREE(context);
5990
 
        return 0;
5991
 
}
5992
 
 
5993
 
 
5994
 
/*
5995
 
 * Each time the context structure is changed, we have binary backward
5996
 
 * compatibility issues.  Instead of modifying the public portions of the
5997
 
 * context structure to add new options, instead, we put them in the internal
5998
 
 * portion of the context structure and provide a set function for these new
5999
 
 * options.
6000
 
 */
6001
 
void
6002
 
smbc_option_set(SMBCCTX *context,
6003
 
                char *option_name,
6004
 
                ... /* option_value */)
6005
 
{
6006
 
        va_list ap;
6007
 
        union {
6008
 
                BOOL b;
6009
 
                smbc_get_auth_data_with_context_fn auth_fn;
6010
 
                void *v;
6011
 
        } option_value;
6012
 
 
6013
 
        va_start(ap, option_name);
6014
 
 
6015
 
        if (strcmp(option_name, "debug_to_stderr") == 0) {
6016
 
                /*
6017
 
                 * Log to standard error instead of standard output.
6018
 
                 */
6019
 
                option_value.b = (BOOL) va_arg(ap, int);
6020
 
                context->internal->_debug_stderr = option_value.b;
6021
 
 
6022
 
        } else if (strcmp(option_name, "debug_to_stderr") == 0) {
6023
 
                /*
6024
 
                 * Log to standard error instead of standard output.
6025
 
                 *
6026
 
                 * This function used to take a third parameter,
6027
 
                 * void *option_value.  Since it was a void* and we needed to
6028
 
                 * pass a boolean, a boolean value was cast to void* to be
6029
 
                 * passed in.  Now that we're using a va_list to retrieve the
6030
 
                 * parameters, the casting kludge is unnecessary.
6031
 
                 *
6032
 
                 * WARNING: DO NOT USE THIS OPTION.
6033
 
                 * This option is retained for backward compatibility.  New
6034
 
                 * applications should use "debug_to_stderr" and properly pass
6035
 
                 * in a boolean (int) value.
6036
 
                 */
6037
 
                option_value.v = va_arg(ap, void *);
6038
 
                context->internal->_debug_stderr =
6039
 
                        (option_value.v == NULL ? False : True);
6040
 
 
6041
 
        } else if (strcmp(option_name, "auth_function") == 0) {
6042
 
                /*
6043
 
                 * Use the new-style authentication function which includes
6044
 
                 * the context.
6045
 
                 */
6046
 
                option_value.auth_fn =
6047
 
                        va_arg(ap, smbc_get_auth_data_with_context_fn);
6048
 
                context->internal->_auth_fn_with_context =
6049
 
                        option_value.auth_fn;
6050
 
        } else if (strcmp(option_name, "user_data") == 0) {
6051
 
                /*
6052
 
                 * Save a user data handle which may be retrieved by the user
6053
 
                 * with smbc_option_get()
6054
 
                 */
6055
 
                option_value.v = va_arg(ap, void *);
6056
 
                context->internal->_user_data = option_value.v;
6057
 
        }
6058
 
 
6059
 
        va_end(ap);
6060
 
}
6061
 
 
6062
 
 
6063
 
/*
6064
 
 * Retrieve the current value of an option
6065
 
 */
6066
 
void *
6067
 
smbc_option_get(SMBCCTX *context,
6068
 
                char *option_name)
6069
 
{
6070
 
        if (strcmp(option_name, "debug_stderr") == 0) {
6071
 
                /*
6072
 
                 * Log to standard error instead of standard output.
6073
 
                 */
6074
 
#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
6075
 
                return (void *) (intptr_t) context->internal->_debug_stderr;
6076
 
#else
6077
 
                return (void *) context->internal->_debug_stderr;
6078
 
#endif
6079
 
        } else if (strcmp(option_name, "auth_function") == 0) {
6080
 
                /*
6081
 
                 * Use the new-style authentication function which includes
6082
 
                 * the context.
6083
 
                 */
6084
 
                return (void *) context->internal->_auth_fn_with_context;
6085
 
        } else if (strcmp(option_name, "user_data") == 0) {
6086
 
                /*
6087
 
                 * Save a user data handle which may be retrieved by the user
6088
 
                 * with smbc_option_get()
6089
 
                 */
6090
 
                return context->internal->_user_data;
6091
 
        }
6092
 
 
6093
 
        return NULL;
6094
 
}
6095
 
 
6096
 
 
6097
 
/*
6098
 
 * Initialise the library etc 
6099
 
 *
6100
 
 * We accept a struct containing handle information.
6101
 
 * valid values for info->debug from 0 to 100,
6102
 
 * and insist that info->fn must be non-null.
6103
 
 */
6104
 
SMBCCTX *
6105
 
smbc_init_context(SMBCCTX *context)
6106
 
{
6107
 
        pstring conf;
6108
 
        int pid;
6109
 
        char *user = NULL;
6110
 
        char *home = NULL;
6111
 
 
6112
 
        if (!context || !context->internal) {
6113
 
                errno = EBADF;
6114
 
                return NULL;
6115
 
        }
6116
 
 
6117
 
        /* Do not initialise the same client twice */
6118
 
        if (context->internal->_initialized) { 
6119
 
                return 0;
6120
 
        }
6121
 
 
6122
 
        if ((!context->callbacks.auth_fn &&
6123
 
             !context->internal->_auth_fn_with_context) ||
6124
 
            context->debug < 0 ||
6125
 
            context->debug > 100) {
6126
 
 
6127
 
                errno = EINVAL;
6128
 
                return NULL;
6129
 
 
6130
 
        }
6131
 
 
6132
 
        if (!smbc_initialized) {
6133
 
                /*
6134
 
                 * Do some library-wide intializations the first time we get
6135
 
                 * called
6136
 
                 */
6137
 
                BOOL conf_loaded = False;
6138
 
 
6139
 
                /* Set this to what the user wants */
6140
 
                DEBUGLEVEL = context->debug;
6141
 
                
6142
 
                load_case_tables();
6143
 
 
6144
 
                setup_logging("libsmbclient", True);
6145
 
                if (context->internal->_debug_stderr) {
6146
 
                        dbf = x_stderr;
6147
 
                        x_setbuf(x_stderr, NULL);
6148
 
                }
6149
 
 
6150
 
                /* Here we would open the smb.conf file if needed ... */
6151
 
                
6152
 
                in_client = True; /* FIXME, make a param */
6153
 
 
6154
 
                home = getenv("HOME");
6155
 
                if (home) {
6156
 
                        slprintf(conf, sizeof(conf), "%s/.smb/smb.conf", home);
6157
 
                        if (lp_load(conf, True, False, False, True)) {
6158
 
                                conf_loaded = True;
6159
 
                        } else {
6160
 
                                DEBUG(5, ("Could not load config file: %s\n",
6161
 
                                          conf));
6162
 
                        }
6163
 
                }
6164
 
 
6165
 
                if (!conf_loaded) {
6166
 
                        /*
6167
 
                         * Well, if that failed, try the dyn_CONFIGFILE
6168
 
                         * Which points to the standard locn, and if that
6169
 
                         * fails, silently ignore it and use the internal
6170
 
                         * defaults ...
6171
 
                         */
6172
 
 
6173
 
                        if (!lp_load(dyn_CONFIGFILE, True, False, False, False)) {
6174
 
                                DEBUG(5, ("Could not load config file: %s\n",
6175
 
                                          dyn_CONFIGFILE));
6176
 
                        } else if (home) {
6177
 
                                /*
6178
 
                                 * We loaded the global config file.  Now lets
6179
 
                                 * load user-specific modifications to the
6180
 
                                 * global config.
6181
 
                                 */
6182
 
                                slprintf(conf, sizeof(conf),
6183
 
                                         "%s/.smb/smb.conf.append", home);
6184
 
                                if (!lp_load(conf, True, False, False, False)) {
6185
 
                                        DEBUG(10,
6186
 
                                              ("Could not append config file: "
6187
 
                                               "%s\n",
6188
 
                                               conf));
6189
 
                                }
6190
 
                        }
6191
 
                }
6192
 
 
6193
 
                load_interfaces();  /* Load the list of interfaces ... */
6194
 
                
6195
 
                reopen_logs();  /* Get logging working ... */
6196
 
        
6197
 
                /* 
6198
 
                 * Block SIGPIPE (from lib/util_sock.c: write())  
6199
 
                 * It is not needed and should not stop execution 
6200
 
                 */
6201
 
                BlockSignals(True, SIGPIPE);
6202
 
                
6203
 
                /* Done with one-time initialisation */
6204
 
                smbc_initialized = 1; 
6205
 
 
6206
 
        }
6207
 
        
6208
 
        if (!context->user) {
6209
 
                /*
6210
 
                 * FIXME: Is this the best way to get the user info? 
6211
 
                 */
6212
 
                user = getenv("USER");
6213
 
                /* walk around as "guest" if no username can be found */
6214
 
                if (!user) context->user = SMB_STRDUP("guest");
6215
 
                else context->user = SMB_STRDUP(user);
6216
 
        }
6217
 
 
6218
 
        if (!context->netbios_name) {
6219
 
                /*
6220
 
                 * We try to get our netbios name from the config. If that
6221
 
                 * fails we fall back on constructing our netbios name from
6222
 
                 * our hostname etc
6223
 
                 */
6224
 
                if (global_myname()) {
6225
 
                        context->netbios_name = SMB_STRDUP(global_myname());
6226
 
                }
6227
 
                else {
6228
 
                        /*
6229
 
                         * Hmmm, I want to get hostname as well, but I am too
6230
 
                         * lazy for the moment
6231
 
                         */
6232
 
                        pid = sys_getpid();
6233
 
                        context->netbios_name = SMB_MALLOC(17);
6234
 
                        if (!context->netbios_name) {
6235
 
                                errno = ENOMEM;
6236
 
                                return NULL;
6237
 
                        }
6238
 
                        slprintf(context->netbios_name, 16,
6239
 
                                 "smbc%s%d", context->user, pid);
6240
 
                }
6241
 
        }
6242
 
 
6243
 
        DEBUG(1, ("Using netbios name %s.\n", context->netbios_name));
6244
 
 
6245
 
        if (!context->workgroup) {
6246
 
                if (lp_workgroup()) {
6247
 
                        context->workgroup = SMB_STRDUP(lp_workgroup());
6248
 
                }
6249
 
                else {
6250
 
                        /* TODO: Think about a decent default workgroup */
6251
 
                        context->workgroup = SMB_STRDUP("samba");
6252
 
                }
6253
 
        }
6254
 
 
6255
 
        DEBUG(1, ("Using workgroup %s.\n", context->workgroup));
6256
 
                                        
6257
 
        /* shortest timeout is 1 second */
6258
 
        if (context->timeout > 0 && context->timeout < 1000) 
6259
 
                context->timeout = 1000;
6260
 
 
6261
 
        /*
6262
 
         * FIXME: Should we check the function pointers here? 
6263
 
         */
6264
 
 
6265
 
        context->internal->_initialized = True;
6266
 
        
6267
 
        return context;
6268
 
}
6269
 
 
6270
 
 
6271
 
/* Return the verion of samba, and thus libsmbclient */
6272
 
const char *
6273
 
smbc_version(void)
6274
 
{
6275
 
        return samba_version_string();
6276
 
}