~vcs-imports/samba/main

« back to all changes in this revision

Viewing changes to source/smbd/service.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/CIFS implementation.
3
 
   service (connection) opening and closing
4
 
   Copyright (C) Andrew Tridgell 1992-1998
5
 
   
6
 
   This program is free software; you can redistribute it and/or modify
7
 
   it under the terms of the GNU General Public License as published by
8
 
   the Free Software Foundation; either version 2 of the License, or
9
 
   (at your option) any later version.
10
 
   
11
 
   This program is distributed in the hope that it will be useful,
12
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
   GNU General Public License for more details.
15
 
   
16
 
   You should have received a copy of the GNU General Public License
17
 
   along with this program; if not, write to the Free Software
18
 
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
 
*/
20
 
 
21
 
#include "includes.h"
22
 
 
23
 
extern userdom_struct current_user_info;
24
 
 
25
 
/****************************************************************************
26
 
 Ensure when setting connectpath it is a canonicalized (no ./ // or ../)
27
 
 absolute path stating in / and not ending in /.
28
 
 Observent people will notice a similarity between this and check_path_syntax :-).
29
 
****************************************************************************/
30
 
 
31
 
void set_conn_connectpath(connection_struct *conn, const pstring connectpath)
32
 
{
33
 
        pstring destname;
34
 
        char *d = destname;
35
 
        const char *s = connectpath;
36
 
        BOOL start_of_name_component = True;
37
 
 
38
 
        *d++ = '/'; /* Always start with root. */
39
 
 
40
 
        while (*s) {
41
 
                if (*s == '/') {
42
 
                        /* Eat multiple '/' */
43
 
                        while (*s == '/') {
44
 
                                s++;
45
 
                        }
46
 
                        if ((d > destname + 1) && (*s != '\0')) {
47
 
                                *d++ = '/';
48
 
                        }
49
 
                        start_of_name_component = True;
50
 
                        continue;
51
 
                }
52
 
 
53
 
                if (start_of_name_component) {
54
 
                        if ((s[0] == '.') && (s[1] == '.') && (s[2] == '/' || s[2] == '\0')) {
55
 
                                /* Uh oh - "/../" or "/..\0" ! */
56
 
 
57
 
                                /* Go past the ../ or .. */
58
 
                                if (s[2] == '/') {
59
 
                                        s += 3;
60
 
                                } else {
61
 
                                        s += 2; /* Go past the .. */
62
 
                                }
63
 
 
64
 
                                /* If  we just added a '/' - delete it */
65
 
                                if ((d > destname) && (*(d-1) == '/')) {
66
 
                                        *(d-1) = '\0';
67
 
                                        d--;
68
 
                                }
69
 
 
70
 
                                /* Are we at the start ? Can't go back further if so. */
71
 
                                if (d <= destname) {
72
 
                                        *d++ = '/'; /* Can't delete root */
73
 
                                        continue;
74
 
                                }
75
 
                                /* Go back one level... */
76
 
                                /* Decrement d first as d points to the *next* char to write into. */
77
 
                                for (d--; d > destname; d--) {
78
 
                                        if (*d == '/') {
79
 
                                                break;
80
 
                                        }
81
 
                                }
82
 
                                /* We're still at the start of a name component, just the previous one. */
83
 
                                continue;
84
 
                        } else if ((s[0] == '.') && ((s[1] == '\0') || s[1] == '/')) {
85
 
                                /* Component of pathname can't be "." only - skip the '.' . */
86
 
                                if (s[1] == '/') {
87
 
                                        s += 2;
88
 
                                } else {
89
 
                                        s++;
90
 
                                }
91
 
                                continue;
92
 
                        }
93
 
                }
94
 
 
95
 
                if (!(*s & 0x80)) {
96
 
                        *d++ = *s++;
97
 
                } else {
98
 
                        switch(next_mb_char_size(s)) {
99
 
                                case 4:
100
 
                                        *d++ = *s++;
101
 
                                case 3:
102
 
                                        *d++ = *s++;
103
 
                                case 2:
104
 
                                        *d++ = *s++;
105
 
                                case 1:
106
 
                                        *d++ = *s++;
107
 
                                        break;
108
 
                                default:
109
 
                                        break;
110
 
                        }
111
 
                }
112
 
                start_of_name_component = False;
113
 
        }
114
 
        *d = '\0';
115
 
 
116
 
        /* And must not end in '/' */
117
 
        if (d > destname + 1 && (*(d-1) == '/')) {
118
 
                *(d-1) = '\0';
119
 
        }
120
 
 
121
 
        DEBUG(10,("set_conn_connectpath: service %s, connectpath = %s\n",
122
 
                lp_servicename(SNUM(conn)), destname ));
123
 
 
124
 
        string_set(&conn->connectpath, destname);
125
 
}
126
 
 
127
 
/****************************************************************************
128
 
 Load parameters specific to a connection/service.
129
 
****************************************************************************/
130
 
 
131
 
BOOL set_current_service(connection_struct *conn, uint16 flags, BOOL do_chdir)
132
 
{
133
 
        static connection_struct *last_conn;
134
 
        static uint16 last_flags;
135
 
        int snum;
136
 
 
137
 
        if (!conn)  {
138
 
                last_conn = NULL;
139
 
                return(False);
140
 
        }
141
 
 
142
 
        conn->lastused_count++;
143
 
 
144
 
        snum = SNUM(conn);
145
 
  
146
 
        if (do_chdir &&
147
 
            vfs_ChDir(conn,conn->connectpath) != 0 &&
148
 
            vfs_ChDir(conn,conn->origpath) != 0) {
149
 
                DEBUG(0,("chdir (%s) failed\n",
150
 
                         conn->connectpath));
151
 
                return(False);
152
 
        }
153
 
 
154
 
        if ((conn == last_conn) && (last_flags == flags)) {
155
 
                return(True);
156
 
        }
157
 
 
158
 
        last_conn = conn;
159
 
        last_flags = flags;
160
 
        
161
 
        /* Obey the client case sensitivity requests - only for clients that support it. */
162
 
        switch (lp_casesensitive(snum)) {
163
 
                case Auto:
164
 
                        {
165
 
                                /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
166
 
                                enum remote_arch_types ra_type = get_remote_arch();
167
 
                                if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
168
 
                                        /* Client can't support per-packet case sensitive pathnames. */
169
 
                                        conn->case_sensitive = False;
170
 
                                } else {
171
 
                                        conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
172
 
                                }
173
 
                        }
174
 
                        break;
175
 
                case True:
176
 
                        conn->case_sensitive = True;
177
 
                        break;
178
 
                default:
179
 
                        conn->case_sensitive = False;
180
 
                        break;
181
 
        }
182
 
        return(True);
183
 
}
184
 
 
185
 
/****************************************************************************
186
 
 Add a home service. Returns the new service number or -1 if fail.
187
 
****************************************************************************/
188
 
 
189
 
int add_home_service(const char *service, const char *username, const char *homedir)
190
 
{
191
 
        int iHomeService;
192
 
 
193
 
        if (!service || !homedir)
194
 
                return -1;
195
 
 
196
 
        if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
197
 
                return -1;
198
 
 
199
 
        /*
200
 
         * If this is a winbindd provided username, remove
201
 
         * the domain component before adding the service.
202
 
         * Log a warning if the "path=" parameter does not
203
 
         * include any macros.
204
 
         */
205
 
 
206
 
        {
207
 
                const char *p = strchr(service,*lp_winbind_separator());
208
 
 
209
 
                /* We only want the 'user' part of the string */
210
 
                if (p) {
211
 
                        service = p + 1;
212
 
                }
213
 
        }
214
 
 
215
 
        if (!lp_add_home(service, iHomeService, username, homedir)) {
216
 
                return -1;
217
 
        }
218
 
        
219
 
        return lp_servicenumber(service);
220
 
 
221
 
}
222
 
 
223
 
 
224
 
/**
225
 
 * Find a service entry.
226
 
 *
227
 
 * @param service is modified (to canonical form??)
228
 
 **/
229
 
 
230
 
int find_service(fstring service)
231
 
{
232
 
        int iService;
233
 
 
234
 
        all_string_sub(service,"\\","/",0);
235
 
 
236
 
        iService = lp_servicenumber(service);
237
 
 
238
 
        /* now handle the special case of a home directory */
239
 
        if (iService < 0) {
240
 
                char *phome_dir = get_user_home_dir(service);
241
 
 
242
 
                if(!phome_dir) {
243
 
                        /*
244
 
                         * Try mapping the servicename, it may
245
 
                         * be a Windows to unix mapped user name.
246
 
                         */
247
 
                        if(map_username(service))
248
 
                                phome_dir = get_user_home_dir(service);
249
 
                }
250
 
 
251
 
                DEBUG(3,("checking for home directory %s gave %s\n",service,
252
 
                        phome_dir?phome_dir:"(NULL)"));
253
 
 
254
 
                iService = add_home_service(service,service /* 'username' */, phome_dir);
255
 
        }
256
 
 
257
 
        /* If we still don't have a service, attempt to add it as a printer. */
258
 
        if (iService < 0) {
259
 
                int iPrinterService;
260
 
 
261
 
                if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0) {
262
 
                        DEBUG(3,("checking whether %s is a valid printer name...\n", service));
263
 
                        if (pcap_printername_ok(service)) {
264
 
                                DEBUG(3,("%s is a valid printer name\n", service));
265
 
                                DEBUG(3,("adding %s as a printer service\n", service));
266
 
                                lp_add_printer(service, iPrinterService);
267
 
                                iService = lp_servicenumber(service);
268
 
                                if (iService < 0) {
269
 
                                        DEBUG(0,("failed to add %s as a printer service!\n", service));
270
 
                                }
271
 
                        } else {
272
 
                                DEBUG(3,("%s is not a valid printer name\n", service));
273
 
                        }
274
 
                }
275
 
        }
276
 
 
277
 
        /* Check for default vfs service?  Unsure whether to implement this */
278
 
        if (iService < 0) {
279
 
        }
280
 
 
281
 
        /* just possibly it's a default service? */
282
 
        if (iService < 0) {
283
 
                char *pdefservice = lp_defaultservice();
284
 
                if (pdefservice && *pdefservice && !strequal(pdefservice,service) && !strstr_m(service,"..")) {
285
 
                        /*
286
 
                         * We need to do a local copy here as lp_defaultservice() 
287
 
                         * returns one of the rotating lp_string buffers that
288
 
                         * could get overwritten by the recursive find_service() call
289
 
                         * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
290
 
                         */
291
 
                        pstring defservice;
292
 
                        pstrcpy(defservice, pdefservice);
293
 
                        iService = find_service(defservice);
294
 
                        if (iService >= 0) {
295
 
                                all_string_sub(service, "_","/",0);
296
 
                                iService = lp_add_service(service, iService);
297
 
                        }
298
 
                }
299
 
        }
300
 
 
301
 
        /* Is it a usershare service ? */
302
 
        if (iService < 0 && *lp_usershare_path()) {
303
 
                /* Ensure the name is canonicalized. */
304
 
                strlower_m(service);
305
 
                iService = load_usershare_service(service);
306
 
        }
307
 
 
308
 
        if (iService >= 0) {
309
 
                if (!VALID_SNUM(iService)) {
310
 
                        DEBUG(0,("Invalid snum %d for %s\n",iService, service));
311
 
                        iService = -1;
312
 
                }
313
 
        }
314
 
 
315
 
        if (iService < 0)
316
 
                DEBUG(3,("find_service() failed to find service %s\n", service));
317
 
 
318
 
        return (iService);
319
 
}
320
 
 
321
 
 
322
 
/****************************************************************************
323
 
 do some basic sainity checks on the share.  
324
 
 This function modifies dev, ecode.
325
 
****************************************************************************/
326
 
 
327
 
static NTSTATUS share_sanity_checks(int snum, fstring dev) 
328
 
{
329
 
        
330
 
        if (!lp_snum_ok(snum) || 
331
 
            !check_access(smbd_server_fd(), 
332
 
                          lp_hostsallow(snum), lp_hostsdeny(snum))) {    
333
 
                return NT_STATUS_ACCESS_DENIED;
334
 
        }
335
 
 
336
 
        if (dev[0] == '?' || !dev[0]) {
337
 
                if (lp_print_ok(snum)) {
338
 
                        fstrcpy(dev,"LPT1:");
339
 
                } else if (strequal(lp_fstype(snum), "IPC")) {
340
 
                        fstrcpy(dev, "IPC");
341
 
                } else {
342
 
                        fstrcpy(dev,"A:");
343
 
                }
344
 
        }
345
 
 
346
 
        strupper_m(dev);
347
 
 
348
 
        if (lp_print_ok(snum)) {
349
 
                if (!strequal(dev, "LPT1:")) {
350
 
                        return NT_STATUS_BAD_DEVICE_TYPE;
351
 
                }
352
 
        } else if (strequal(lp_fstype(snum), "IPC")) {
353
 
                if (!strequal(dev, "IPC")) {
354
 
                        return NT_STATUS_BAD_DEVICE_TYPE;
355
 
                }
356
 
        } else if (!strequal(dev, "A:")) {
357
 
                return NT_STATUS_BAD_DEVICE_TYPE;
358
 
        }
359
 
 
360
 
        /* Behave as a printer if we are supposed to */
361
 
        if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
362
 
                fstrcpy(dev, "LPT1:");
363
 
        }
364
 
 
365
 
        return NT_STATUS_OK;
366
 
}
367
 
 
368
 
static NTSTATUS find_forced_user(int snum, BOOL vuser_is_guest,
369
 
                                 uid_t *uid, gid_t *gid, fstring username,
370
 
                                 struct nt_user_token **token)
371
 
{
372
 
        TALLOC_CTX *mem_ctx;
373
 
        char *fuser, *found_username;
374
 
        struct nt_user_token *tmp_token;
375
 
        NTSTATUS result;
376
 
 
377
 
        if (!(mem_ctx = talloc_new(NULL))) {
378
 
                DEBUG(0, ("talloc_new failed\n"));
379
 
                return NT_STATUS_NO_MEMORY;
380
 
        }
381
 
 
382
 
        if (!(fuser = talloc_string_sub(mem_ctx, lp_force_user(snum), "%S",
383
 
                                        lp_servicename(snum)))) {
384
 
                TALLOC_FREE(mem_ctx);
385
 
                return NT_STATUS_NO_MEMORY;
386
 
                
387
 
        }
388
 
 
389
 
        result = create_token_from_username(mem_ctx, fuser, vuser_is_guest,
390
 
                                            uid, gid, &found_username,
391
 
                                            &tmp_token);
392
 
        if (!NT_STATUS_IS_OK(result)) {
393
 
                TALLOC_FREE(mem_ctx);
394
 
                return result;
395
 
        }
396
 
 
397
 
        if (!(*token = dup_nt_token(NULL, tmp_token))) {
398
 
                TALLOC_FREE(mem_ctx);
399
 
                return NT_STATUS_NO_MEMORY;
400
 
        }
401
 
 
402
 
        fstrcpy(username, found_username);
403
 
 
404
 
        TALLOC_FREE(mem_ctx);
405
 
        return NT_STATUS_OK;
406
 
}
407
 
 
408
 
/*
409
 
 * Go through lookup_name etc to find the force'd group.  
410
 
 *
411
 
 * Create a new token from src_token, replacing the primary group sid with the
412
 
 * one found.
413
 
 */
414
 
 
415
 
static NTSTATUS find_forced_group(BOOL force_user,
416
 
                                  int snum, const char *username,
417
 
                                  DOM_SID *pgroup_sid,
418
 
                                  gid_t *pgid)
419
 
{
420
 
        NTSTATUS result = NT_STATUS_NO_SUCH_GROUP;
421
 
        TALLOC_CTX *mem_ctx;
422
 
        DOM_SID group_sid;
423
 
        enum SID_NAME_USE type;
424
 
        char *groupname;
425
 
        BOOL user_must_be_member = False;
426
 
        gid_t gid;
427
 
 
428
 
        mem_ctx = talloc_new(NULL);
429
 
        if (mem_ctx == NULL) {
430
 
                DEBUG(0, ("talloc_new failed\n"));
431
 
                return NT_STATUS_NO_MEMORY;
432
 
        }
433
 
 
434
 
        groupname = talloc_strdup(mem_ctx, lp_force_group(snum));
435
 
        if (groupname == NULL) {
436
 
                DEBUG(1, ("talloc_strdup failed\n"));
437
 
                result = NT_STATUS_NO_MEMORY;
438
 
                goto done;
439
 
        }
440
 
 
441
 
        if (groupname[0] == '+') {
442
 
                user_must_be_member = True;
443
 
                groupname += 1;
444
 
        }
445
 
 
446
 
        groupname = talloc_string_sub(mem_ctx, groupname,
447
 
                                      "%S", lp_servicename(snum));
448
 
 
449
 
        if (!lookup_name(mem_ctx, groupname,
450
 
                         LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
451
 
                         NULL, NULL, &group_sid, &type)) {
452
 
                DEBUG(10, ("lookup_name(%s) failed\n",
453
 
                           groupname));
454
 
                goto done;
455
 
        }
456
 
 
457
 
        if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
458
 
            (type != SID_NAME_WKN_GRP)) {
459
 
                DEBUG(10, ("%s is a %s, not a group\n", groupname,
460
 
                           sid_type_lookup(type)));
461
 
                goto done;
462
 
        }
463
 
 
464
 
        if (!sid_to_gid(&group_sid, &gid)) {
465
 
                DEBUG(10, ("sid_to_gid(%s) for %s failed\n",
466
 
                           sid_string_static(&group_sid), groupname));
467
 
                goto done;
468
 
        }
469
 
 
470
 
        /*
471
 
         * If the user has been forced and the forced group starts with a '+',
472
 
         * then we only set the group to be the forced group if the forced
473
 
         * user is a member of that group.  Otherwise, the meaning of the '+'
474
 
         * would be ignored.
475
 
         */
476
 
 
477
 
        if (force_user && user_must_be_member) {
478
 
                if (user_in_group_sid(username, &group_sid)) {
479
 
                        sid_copy(pgroup_sid, &group_sid);
480
 
                        *pgid = gid;
481
 
                        DEBUG(3,("Forced group %s for member %s\n",
482
 
                                 groupname, username));
483
 
                }
484
 
        } else {
485
 
                sid_copy(pgroup_sid, &group_sid);
486
 
                *pgid = gid;
487
 
                DEBUG(3,("Forced group %s\n", groupname));
488
 
        }
489
 
 
490
 
        result = NT_STATUS_OK;
491
 
 done:
492
 
        TALLOC_FREE(mem_ctx);
493
 
        return result;
494
 
}
495
 
 
496
 
/****************************************************************************
497
 
  Make a connection, given the snum to connect to, and the vuser of the
498
 
  connecting user if appropriate.
499
 
****************************************************************************/
500
 
 
501
 
static connection_struct *make_connection_snum(int snum, user_struct *vuser,
502
 
                                               DATA_BLOB password, 
503
 
                                               const char *pdev,
504
 
                                               NTSTATUS *status)
505
 
{
506
 
        struct passwd *pass = NULL;
507
 
        BOOL guest = False;
508
 
        connection_struct *conn;
509
 
        SMB_STRUCT_STAT st;
510
 
        fstring user;
511
 
        fstring dev;
512
 
        int ret;
513
 
 
514
 
        *user = 0;
515
 
        fstrcpy(dev, pdev);
516
 
        SET_STAT_INVALID(st);
517
 
 
518
 
        if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
519
 
                return NULL;
520
 
        }       
521
 
 
522
 
        conn = conn_new();
523
 
        if (!conn) {
524
 
                DEBUG(0,("Couldn't find free connection.\n"));
525
 
                *status = NT_STATUS_INSUFFICIENT_RESOURCES;
526
 
                return NULL;
527
 
        }
528
 
 
529
 
        conn->nt_user_token = NULL;
530
 
 
531
 
        if (lp_guest_only(snum)) {
532
 
                const char *guestname = lp_guestaccount();
533
 
                NTSTATUS status2;
534
 
                char *found_username;
535
 
                guest = True;
536
 
                pass = getpwnam_alloc(NULL, guestname);
537
 
                if (!pass) {
538
 
                        DEBUG(0,("make_connection_snum: Invalid guest "
539
 
                                 "account %s??\n",guestname));
540
 
                        conn_free(conn);
541
 
                        *status = NT_STATUS_NO_SUCH_USER;
542
 
                        return NULL;
543
 
                }
544
 
                status2 = create_token_from_username(NULL, pass->pw_name, True,
545
 
                                                     &conn->uid, &conn->gid,
546
 
                                                     &found_username,
547
 
                                                     &conn->nt_user_token);
548
 
                if (!NT_STATUS_IS_OK(status2)) {
549
 
                        conn_free(conn);
550
 
                        *status = status2;
551
 
                        return NULL;
552
 
                }
553
 
                fstrcpy(user, found_username);
554
 
                string_set(&conn->user,user);
555
 
                conn->force_user = True;
556
 
                TALLOC_FREE(pass);
557
 
                DEBUG(3,("Guest only user %s\n",user));
558
 
        } else if (vuser) {
559
 
                if (vuser->guest) {
560
 
                        if (!lp_guest_ok(snum)) {
561
 
                                DEBUG(2, ("guest user (from session setup) "
562
 
                                          "not permitted to access this share "
563
 
                                          "(%s)\n", lp_servicename(snum)));
564
 
                                      conn_free(conn);
565
 
                                      *status = NT_STATUS_ACCESS_DENIED;
566
 
                                      return NULL;
567
 
                        }
568
 
                } else {
569
 
                        if (!user_ok_token(vuser->user.unix_name,
570
 
                                           vuser->nt_user_token, snum)) {
571
 
                                DEBUG(2, ("user '%s' (from session setup) not "
572
 
                                          "permitted to access this share "
573
 
                                          "(%s)\n", vuser->user.unix_name,
574
 
                                          lp_servicename(snum)));
575
 
                                conn_free(conn);
576
 
                                *status = NT_STATUS_ACCESS_DENIED;
577
 
                                return NULL;
578
 
                        }
579
 
                }
580
 
                conn->vuid = vuser->vuid;
581
 
                conn->uid = vuser->uid;
582
 
                conn->gid = vuser->gid;
583
 
                string_set(&conn->user,vuser->user.unix_name);
584
 
                fstrcpy(user,vuser->user.unix_name);
585
 
                guest = vuser->guest; 
586
 
        } else if (lp_security() == SEC_SHARE) {
587
 
                NTSTATUS status2;
588
 
                char *found_username;
589
 
                /* add it as a possible user name if we 
590
 
                   are in share mode security */
591
 
                add_session_user(lp_servicename(snum));
592
 
                /* shall we let them in? */
593
 
                if (!authorise_login(snum,user,password,&guest)) {
594
 
                        DEBUG( 2, ( "Invalid username/password for [%s]\n", 
595
 
                                    lp_servicename(snum)) );
596
 
                        conn_free(conn);
597
 
                        *status = NT_STATUS_WRONG_PASSWORD;
598
 
                        return NULL;
599
 
                }
600
 
                pass = Get_Pwnam(user);
601
 
                status2 = create_token_from_username(NULL, pass->pw_name, True,
602
 
                                                     &conn->uid, &conn->gid,
603
 
                                                     &found_username,
604
 
                                                     &conn->nt_user_token);
605
 
                if (!NT_STATUS_IS_OK(status2)) {
606
 
                        conn_free(conn);
607
 
                        *status = status2;
608
 
                        return NULL;
609
 
                }
610
 
                fstrcpy(user, found_username);
611
 
                string_set(&conn->user,user);
612
 
                conn->force_user = True;
613
 
        } else {
614
 
                DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
615
 
                conn_free(conn);
616
 
                *status = NT_STATUS_ACCESS_DENIED;
617
 
                return NULL;
618
 
        }
619
 
 
620
 
        add_session_user(user);
621
 
 
622
 
        safe_strcpy(conn->client_address, client_addr(), 
623
 
                    sizeof(conn->client_address)-1);
624
 
        conn->num_files_open = 0;
625
 
        conn->lastused = conn->lastused_count = time(NULL);
626
 
        conn->params->service = snum;
627
 
        conn->used = True;
628
 
        conn->printer = (strncmp(dev,"LPT",3) == 0);
629
 
        conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
630
 
                      ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
631
 
        conn->dirptr = NULL;
632
 
 
633
 
        /* Case options for the share. */
634
 
        if (lp_casesensitive(snum) == Auto) {
635
 
                /* We will be setting this per packet. Set to be case
636
 
                 * insensitive for now. */
637
 
                conn->case_sensitive = False;
638
 
        } else {
639
 
                conn->case_sensitive = (BOOL)lp_casesensitive(snum);
640
 
        }
641
 
 
642
 
        conn->case_preserve = lp_preservecase(snum);
643
 
        conn->short_case_preserve = lp_shortpreservecase(snum);
644
 
 
645
 
        conn->veto_list = NULL;
646
 
        conn->hide_list = NULL;
647
 
        conn->veto_oplock_list = NULL;
648
 
        conn->aio_write_behind_list = NULL;
649
 
        string_set(&conn->dirpath,"");
650
 
        string_set(&conn->user,user);
651
 
 
652
 
        conn->read_only = lp_readonly(SNUM(conn));
653
 
        conn->admin_user = False;
654
 
 
655
 
        /*
656
 
         * If force user is true, then store the given userid and the gid of
657
 
         * the user we're forcing.
658
 
         * For auxiliary groups see below.
659
 
         */
660
 
        
661
 
        if (*lp_force_user(snum)) {
662
 
                NTSTATUS status2;
663
 
 
664
 
                status2 = find_forced_user(snum,
665
 
                                           (vuser != NULL) && vuser->guest,
666
 
                                           &conn->uid, &conn->gid, user,
667
 
                                           &conn->nt_user_token);
668
 
                if (!NT_STATUS_IS_OK(status2)) {
669
 
                        conn_free(conn);
670
 
                        *status = status2;
671
 
                        return NULL;
672
 
                }
673
 
                string_set(&conn->user,user);
674
 
                conn->force_user = True;
675
 
                DEBUG(3,("Forced user %s\n",user));       
676
 
        }
677
 
 
678
 
        /*
679
 
         * If force group is true, then override
680
 
         * any groupid stored for the connecting user.
681
 
         */
682
 
        
683
 
        if (*lp_force_group(snum)) {
684
 
                NTSTATUS status2;
685
 
                DOM_SID group_sid;
686
 
 
687
 
                status2 = find_forced_group(conn->force_user,
688
 
                                            snum, user,
689
 
                                            &group_sid, &conn->gid);
690
 
                if (!NT_STATUS_IS_OK(status2)) {
691
 
                        conn_free(conn);
692
 
                        *status = status2;
693
 
                        return NULL;
694
 
                }
695
 
 
696
 
                if ((conn->nt_user_token == NULL) && (vuser != NULL)) {
697
 
 
698
 
                        /* Not force user and not security=share, but force
699
 
                         * group. vuser has a token to copy */
700
 
                        
701
 
                        conn->nt_user_token = dup_nt_token(
702
 
                                NULL, vuser->nt_user_token);
703
 
                        if (conn->nt_user_token == NULL) {
704
 
                                DEBUG(0, ("dup_nt_token failed\n"));
705
 
                                conn_free(conn);
706
 
                                *status = NT_STATUS_NO_MEMORY;
707
 
                                return NULL;
708
 
                        }
709
 
                }
710
 
 
711
 
                /* If conn->nt_user_token is still NULL, we have
712
 
                 * security=share. This means ignore the SID, as we had no
713
 
                 * vuser to copy from */
714
 
 
715
 
                if (conn->nt_user_token != NULL) {
716
 
                        /* Overwrite the primary group sid */
717
 
                        sid_copy(&conn->nt_user_token->user_sids[1],
718
 
                                 &group_sid);
719
 
 
720
 
                }
721
 
                conn->force_group = True;
722
 
        }
723
 
 
724
 
        if (conn->nt_user_token != NULL) {
725
 
                size_t i;
726
 
 
727
 
                /* We have a share-specific token from force [user|group].
728
 
                 * This means we have to create the list of unix groups from
729
 
                 * the list of sids. */
730
 
 
731
 
                conn->ngroups = 0;
732
 
                conn->groups = NULL;
733
 
 
734
 
                for (i=0; i<conn->nt_user_token->num_sids; i++) {
735
 
                        gid_t gid;
736
 
                        DOM_SID *sid = &conn->nt_user_token->user_sids[i];
737
 
 
738
 
                        if (!sid_to_gid(sid, &gid)) {
739
 
                                DEBUG(10, ("Could not convert SID %s to gid, "
740
 
                                           "ignoring it\n",
741
 
                                           sid_string_static(sid)));
742
 
                                continue;
743
 
                        }
744
 
                        add_gid_to_array_unique(NULL, gid, &conn->groups,
745
 
                                                &conn->ngroups);
746
 
                }
747
 
        }
748
 
 
749
 
        {
750
 
                pstring s;
751
 
                pstrcpy(s,lp_pathname(snum));
752
 
                standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
753
 
                                      conn->connectpath, conn->gid,
754
 
                                      get_current_username(),
755
 
                                      current_user_info.domain,
756
 
                                      s, sizeof(s));
757
 
                set_conn_connectpath(conn,s);
758
 
                DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
759
 
                         lp_servicename(snum)));
760
 
        }
761
 
 
762
 
        /*
763
 
         * New code to check if there's a share security descripter
764
 
         * added from NT server manager. This is done after the
765
 
         * smb.conf checks are done as we need a uid and token. JRA.
766
 
         *
767
 
         */
768
 
 
769
 
        {
770
 
                BOOL can_write = share_access_check(conn, snum, vuser,
771
 
                                                    FILE_WRITE_DATA);
772
 
 
773
 
                if (!can_write) {
774
 
                        if (!share_access_check(conn, snum, vuser,
775
 
                                                FILE_READ_DATA)) {
776
 
                                /* No access, read or write. */
777
 
                                DEBUG(0,("make_connection: connection to %s "
778
 
                                         "denied due to security "
779
 
                                         "descriptor.\n",
780
 
                                          lp_servicename(snum)));
781
 
                                conn_free(conn);
782
 
                                *status = NT_STATUS_ACCESS_DENIED;
783
 
                                return NULL;
784
 
                        } else {
785
 
                                conn->read_only = True;
786
 
                        }
787
 
                }
788
 
        }
789
 
        /* Initialise VFS function pointers */
790
 
 
791
 
        if (!smbd_vfs_init(conn)) {
792
 
                DEBUG(0, ("vfs_init failed for service %s\n",
793
 
                          lp_servicename(snum)));
794
 
                conn_free(conn);
795
 
                *status = NT_STATUS_BAD_NETWORK_NAME;
796
 
                return NULL;
797
 
        }
798
 
 
799
 
        /*
800
 
         * If widelinks are disallowed we need to canonicalise the connect
801
 
         * path here to ensure we don't have any symlinks in the
802
 
         * connectpath. We will be checking all paths on this connection are
803
 
         * below this directory. We must do this after the VFS init as we
804
 
         * depend on the realpath() pointer in the vfs table. JRA.
805
 
         */
806
 
        if (!lp_widelinks(snum)) {
807
 
                pstring s;
808
 
                pstrcpy(s,conn->connectpath);
809
 
                canonicalize_path(conn, s);
810
 
                set_conn_connectpath(conn,s);
811
 
        }
812
 
 
813
 
/* ROOT Activities: */  
814
 
        /* check number of connections */
815
 
        if (!claim_connection(conn,
816
 
                              lp_servicename(snum),
817
 
                              lp_max_connections(snum),
818
 
                              False,0)) {
819
 
                DEBUG(1,("too many connections - rejected\n"));
820
 
                conn_free(conn);
821
 
                *status = NT_STATUS_INSUFFICIENT_RESOURCES;
822
 
                return NULL;
823
 
        }  
824
 
 
825
 
        /* Preexecs are done here as they might make the dir we are to ChDir
826
 
         * to below */
827
 
        /* execute any "root preexec = " line */
828
 
        if (*lp_rootpreexec(snum)) {
829
 
                pstring cmd;
830
 
                pstrcpy(cmd,lp_rootpreexec(snum));
831
 
                standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
832
 
                                      conn->connectpath, conn->gid,
833
 
                                      get_current_username(),
834
 
                                      current_user_info.domain,
835
 
                                      cmd, sizeof(cmd));
836
 
                DEBUG(5,("cmd=%s\n",cmd));
837
 
                ret = smbrun(cmd,NULL);
838
 
                if (ret != 0 && lp_rootpreexec_close(snum)) {
839
 
                        DEBUG(1,("root preexec gave %d - failing "
840
 
                                 "connection\n", ret));
841
 
                        yield_connection(conn, lp_servicename(snum));
842
 
                        conn_free(conn);
843
 
                        *status = NT_STATUS_ACCESS_DENIED;
844
 
                        return NULL;
845
 
                }
846
 
        }
847
 
 
848
 
/* USER Activites: */
849
 
        if (!change_to_user(conn, conn->vuid)) {
850
 
                /* No point continuing if they fail the basic checks */
851
 
                DEBUG(0,("Can't become connected user!\n"));
852
 
                yield_connection(conn, lp_servicename(snum));
853
 
                conn_free(conn);
854
 
                *status = NT_STATUS_LOGON_FAILURE;
855
 
                return NULL;
856
 
        }
857
 
 
858
 
        /* Remember that a different vuid can connect later without these
859
 
         * checks... */
860
 
        
861
 
        /* Preexecs are done here as they might make the dir we are to ChDir
862
 
         * to below */
863
 
 
864
 
        /* execute any "preexec = " line */
865
 
        if (*lp_preexec(snum)) {
866
 
                pstring cmd;
867
 
                pstrcpy(cmd,lp_preexec(snum));
868
 
                standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
869
 
                                      conn->connectpath, conn->gid,
870
 
                                      get_current_username(),
871
 
                                      current_user_info.domain,
872
 
                                      cmd, sizeof(cmd));
873
 
                ret = smbrun(cmd,NULL);
874
 
                if (ret != 0 && lp_preexec_close(snum)) {
875
 
                        DEBUG(1,("preexec gave %d - failing connection\n",
876
 
                                 ret));
877
 
                        change_to_root_user();
878
 
                        yield_connection(conn, lp_servicename(snum));
879
 
                        conn_free(conn);
880
 
                        *status = NT_STATUS_ACCESS_DENIED;
881
 
                        return NULL;
882
 
                }
883
 
        }
884
 
 
885
 
#ifdef WITH_FAKE_KASERVER
886
 
        if (lp_afs_share(snum)) {
887
 
                afs_login(conn);
888
 
        }
889
 
#endif
890
 
        
891
 
        /* Add veto/hide lists */
892
 
        if (!IS_IPC(conn) && !IS_PRINT(conn)) {
893
 
                set_namearray( &conn->veto_list, lp_veto_files(snum));
894
 
                set_namearray( &conn->hide_list, lp_hide_files(snum));
895
 
                set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
896
 
        }
897
 
        
898
 
        /* Invoke VFS make connection hook - do this before the VFS_STAT call
899
 
           to allow any filesystems needing user credentials to initialize
900
 
           themselves. */
901
 
 
902
 
        if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
903
 
                DEBUG(0,("make_connection: VFS make connection failed!\n"));
904
 
                change_to_root_user();
905
 
                yield_connection(conn, lp_servicename(snum));
906
 
                conn_free(conn);
907
 
                *status = NT_STATUS_UNSUCCESSFUL;
908
 
                return NULL;
909
 
        }
910
 
 
911
 
        /* win2000 does not check the permissions on the directory
912
 
           during the tree connect, instead relying on permission
913
 
           check during individual operations. To match this behaviour
914
 
           I have disabled this chdir check (tridge) */
915
 
        /* the alternative is just to check the directory exists */
916
 
        if ((ret = SMB_VFS_STAT(conn, conn->connectpath, &st)) != 0 ||
917
 
            !S_ISDIR(st.st_mode)) {
918
 
                if (ret == 0 && !S_ISDIR(st.st_mode)) {
919
 
                        DEBUG(0,("'%s' is not a directory, when connecting to "
920
 
                                 "[%s]\n", conn->connectpath,
921
 
                                 lp_servicename(snum)));
922
 
                } else {
923
 
                        DEBUG(0,("'%s' does not exist or permission denied "
924
 
                                 "when connecting to [%s] Error was %s\n",
925
 
                                 conn->connectpath, lp_servicename(snum),
926
 
                                 strerror(errno) ));
927
 
                }
928
 
                change_to_root_user();
929
 
                /* Call VFS disconnect hook */    
930
 
                SMB_VFS_DISCONNECT(conn);
931
 
                yield_connection(conn, lp_servicename(snum));
932
 
                conn_free(conn);
933
 
                *status = NT_STATUS_BAD_NETWORK_NAME;
934
 
                return NULL;
935
 
        }
936
 
        
937
 
        string_set(&conn->origpath,conn->connectpath);
938
 
        
939
 
#if SOFTLINK_OPTIMISATION
940
 
        /* resolve any soft links early if possible */
941
 
        if (vfs_ChDir(conn,conn->connectpath) == 0) {
942
 
                pstring s;
943
 
                pstrcpy(s,conn->connectpath);
944
 
                vfs_GetWd(conn,s);
945
 
                set_conn_connectpath(conn,s);
946
 
                vfs_ChDir(conn,conn->connectpath);
947
 
        }
948
 
#endif
949
 
        
950
 
        /*
951
 
         * Print out the 'connected as' stuff here as we need
952
 
         * to know the effective uid and gid we will be using
953
 
         * (at least initially).
954
 
         */
955
 
 
956
 
        if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
957
 
                dbgtext( "%s (%s) ", get_remote_machine_name(),
958
 
                         conn->client_address );
959
 
                dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
960
 
                dbgtext( "connect to service %s ", lp_servicename(snum) );
961
 
                dbgtext( "initially as user %s ", user );
962
 
                dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
963
 
                dbgtext( "(pid %d)\n", (int)sys_getpid() );
964
 
        }
965
 
        
966
 
        /* Setup the minimum value for a change notify wait time (seconds). */
967
 
        set_change_notify_timeout(lp_change_notify_timeout(snum));
968
 
 
969
 
        /* we've finished with the user stuff - go back to root */
970
 
        change_to_root_user();
971
 
        return(conn);
972
 
}
973
 
 
974
 
/***************************************************************************************
975
 
 Simple wrapper function for make_connection() to include a call to 
976
 
 vfs_chdir()
977
 
 **************************************************************************************/
978
 
 
979
 
connection_struct *make_connection_with_chdir(const char *service_in,
980
 
                                              DATA_BLOB password, 
981
 
                                              const char *dev, uint16 vuid,
982
 
                                              NTSTATUS *status)
983
 
{
984
 
        connection_struct *conn = NULL;
985
 
        
986
 
        conn = make_connection(service_in, password, dev, vuid, status);
987
 
        
988
 
        /*
989
 
         * make_connection() does not change the directory for us any more
990
 
         * so we have to do it as a separate step  --jerry
991
 
         */
992
 
         
993
 
        if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
994
 
                DEBUG(0,("move_driver_to_download_area: Can't change "
995
 
                         "directory to %s for [print$] (%s)\n",
996
 
                         conn->connectpath,strerror(errno)));
997
 
                yield_connection(conn, lp_servicename(SNUM(conn)));
998
 
                conn_free(conn);
999
 
                *status = NT_STATUS_UNSUCCESSFUL;
1000
 
                return NULL;
1001
 
        }
1002
 
        
1003
 
        return conn;
1004
 
}
1005
 
 
1006
 
/****************************************************************************
1007
 
 Make a connection to a service.
1008
 
 *
1009
 
 * @param service 
1010
 
****************************************************************************/
1011
 
 
1012
 
connection_struct *make_connection(const char *service_in, DATA_BLOB password, 
1013
 
                                   const char *pdev, uint16 vuid,
1014
 
                                   NTSTATUS *status)
1015
 
{
1016
 
        uid_t euid;
1017
 
        user_struct *vuser = NULL;
1018
 
        fstring service;
1019
 
        fstring dev;
1020
 
        int snum = -1;
1021
 
 
1022
 
        fstrcpy(dev, pdev);
1023
 
 
1024
 
        /* This must ONLY BE CALLED AS ROOT. As it exits this function as
1025
 
         * root. */
1026
 
        if (!non_root_mode() && (euid = geteuid()) != 0) {
1027
 
                DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
1028
 
                         "(%u)\n", (unsigned int)euid ));
1029
 
                smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
1030
 
        }
1031
 
 
1032
 
        if(lp_security() != SEC_SHARE) {
1033
 
                vuser = get_valid_user_struct(vuid);
1034
 
                if (!vuser) {
1035
 
                        DEBUG(1,("make_connection: refusing to connect with "
1036
 
                                 "no session setup\n"));
1037
 
                        *status = NT_STATUS_ACCESS_DENIED;
1038
 
                        return NULL;
1039
 
                }
1040
 
        }
1041
 
 
1042
 
        /* Logic to try and connect to the correct [homes] share, preferably
1043
 
           without too many getpwnam() lookups.  This is particulary nasty for
1044
 
           winbind usernames, where the share name isn't the same as unix
1045
 
           username.
1046
 
 
1047
 
           The snum of the homes share is stored on the vuser at session setup
1048
 
           time.
1049
 
        */
1050
 
 
1051
 
        if (strequal(service_in,HOMES_NAME)) {
1052
 
                if(lp_security() != SEC_SHARE) {
1053
 
                        DATA_BLOB no_pw = data_blob(NULL, 0);
1054
 
                        if (vuser->homes_snum == -1) {
1055
 
                                DEBUG(2, ("[homes] share not available for "
1056
 
                                          "this user because it was not found "
1057
 
                                          "or created at session setup "
1058
 
                                          "time\n"));
1059
 
                                *status = NT_STATUS_BAD_NETWORK_NAME;
1060
 
                                return NULL;
1061
 
                        }
1062
 
                        DEBUG(5, ("making a connection to [homes] service "
1063
 
                                  "created at session setup time\n"));
1064
 
                        return make_connection_snum(vuser->homes_snum,
1065
 
                                                    vuser, no_pw, 
1066
 
                                                    dev, status);
1067
 
                } else {
1068
 
                        /* Security = share. Try with
1069
 
                         * current_user_info.smb_name as the username.  */
1070
 
                        if (*current_user_info.smb_name) {
1071
 
                                fstring unix_username;
1072
 
                                fstrcpy(unix_username,
1073
 
                                        current_user_info.smb_name);
1074
 
                                map_username(unix_username);
1075
 
                                snum = find_service(unix_username);
1076
 
                        } 
1077
 
                        if (snum != -1) {
1078
 
                                DEBUG(5, ("making a connection to 'homes' "
1079
 
                                          "service %s based on "
1080
 
                                          "security=share\n", service_in));
1081
 
                                return make_connection_snum(snum, NULL,
1082
 
                                                            password,
1083
 
                                                            dev, status);
1084
 
                        }
1085
 
                }
1086
 
        } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
1087
 
                   && strequal(service_in,
1088
 
                               lp_servicename(vuser->homes_snum))) {
1089
 
                DATA_BLOB no_pw = data_blob(NULL, 0);
1090
 
                DEBUG(5, ("making a connection to 'homes' service [%s] "
1091
 
                          "created at session setup time\n", service_in));
1092
 
                return make_connection_snum(vuser->homes_snum,
1093
 
                                            vuser, no_pw, 
1094
 
                                            dev, status);
1095
 
        }
1096
 
        
1097
 
        fstrcpy(service, service_in);
1098
 
 
1099
 
        strlower_m(service);
1100
 
 
1101
 
        snum = find_service(service);
1102
 
 
1103
 
        if (snum < 0) {
1104
 
                if (strequal(service,"IPC$") ||
1105
 
                    (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
1106
 
                        DEBUG(3,("refusing IPC connection to %s\n", service));
1107
 
                        *status = NT_STATUS_ACCESS_DENIED;
1108
 
                        return NULL;
1109
 
                }
1110
 
 
1111
 
                DEBUG(0,("%s (%s) couldn't find service %s\n",
1112
 
                         get_remote_machine_name(), client_addr(), service));
1113
 
                *status = NT_STATUS_BAD_NETWORK_NAME;
1114
 
                return NULL;
1115
 
        }
1116
 
 
1117
 
        /* Handle non-Dfs clients attempting connections to msdfs proxy */
1118
 
        if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0'))  {
1119
 
                DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1120
 
                          "(pointing to %s)\n", 
1121
 
                        service, lp_msdfs_proxy(snum)));
1122
 
                *status = NT_STATUS_BAD_NETWORK_NAME;
1123
 
                return NULL;
1124
 
        }
1125
 
 
1126
 
        DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1127
 
 
1128
 
        return make_connection_snum(snum, vuser,
1129
 
                                    password,
1130
 
                                    dev, status);
1131
 
}
1132
 
 
1133
 
/****************************************************************************
1134
 
 Close a cnum.
1135
 
****************************************************************************/
1136
 
 
1137
 
void close_cnum(connection_struct *conn, uint16 vuid)
1138
 
{
1139
 
        if (IS_IPC(conn)) {
1140
 
                pipe_close_conn(conn);
1141
 
        } else {
1142
 
                file_close_conn(conn);
1143
 
                dptr_closecnum(conn);
1144
 
        }
1145
 
 
1146
 
        change_to_root_user();
1147
 
 
1148
 
        DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
1149
 
                                 get_remote_machine_name(),
1150
 
                                 conn->client_address,
1151
 
                                 lp_servicename(SNUM(conn))));
1152
 
 
1153
 
        /* Call VFS disconnect hook */    
1154
 
        SMB_VFS_DISCONNECT(conn);
1155
 
 
1156
 
        yield_connection(conn, lp_servicename(SNUM(conn)));
1157
 
 
1158
 
        /* make sure we leave the directory available for unmount */
1159
 
        vfs_ChDir(conn, "/");
1160
 
 
1161
 
        /* execute any "postexec = " line */
1162
 
        if (*lp_postexec(SNUM(conn)) && 
1163
 
            change_to_user(conn, vuid))  {
1164
 
                pstring cmd;
1165
 
                pstrcpy(cmd,lp_postexec(SNUM(conn)));
1166
 
                standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
1167
 
                                      conn->connectpath, conn->gid,
1168
 
                                      get_current_username(),
1169
 
                                      current_user_info.domain,
1170
 
                                      cmd, sizeof(cmd));
1171
 
                smbrun(cmd,NULL);
1172
 
                change_to_root_user();
1173
 
        }
1174
 
 
1175
 
        change_to_root_user();
1176
 
        /* execute any "root postexec = " line */
1177
 
        if (*lp_rootpostexec(SNUM(conn)))  {
1178
 
                pstring cmd;
1179
 
                pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
1180
 
                standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
1181
 
                                      conn->connectpath, conn->gid,
1182
 
                                      get_current_username(),
1183
 
                                      current_user_info.domain,
1184
 
                                      cmd, sizeof(cmd));
1185
 
                smbrun(cmd,NULL);
1186
 
        }
1187
 
 
1188
 
        conn_free(conn);
1189
 
}