r1643: syncing all changes from 3.0 and hopefully get 3.0.6rc2 out tomorrow
[Samba.git] / source / smbd / service.c
blob794b5332ac5eaaf7fff503faac68bbb4d60b94eb
1 /*
2 Unix SMB/CIFS implementation.
3 service (connection) opening and closing
4 Copyright (C) Andrew Tridgell 1992-1998
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.
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.
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.
21 #include "includes.h"
23 extern struct timeval smb_last_time;
24 extern userdom_struct current_user_info;
27 /****************************************************************************
28 Load parameters specific to a connection/service.
29 ****************************************************************************/
31 BOOL set_current_service(connection_struct *conn, uint16 flags, BOOL do_chdir)
33 extern char magic_char;
34 static connection_struct *last_conn;
35 static uint16 last_flags;
36 int snum;
38 if (!conn) {
39 last_conn = NULL;
40 return(False);
43 conn->lastused = smb_last_time.tv_sec;
45 snum = SNUM(conn);
47 if (do_chdir &&
48 vfs_ChDir(conn,conn->connectpath) != 0 &&
49 vfs_ChDir(conn,conn->origpath) != 0) {
50 DEBUG(0,("chdir (%s) failed\n",
51 conn->connectpath));
52 return(False);
55 if ((conn == last_conn) && (last_flags == flags)) {
56 return(True);
59 last_conn = conn;
60 last_flags = flags;
62 /* Obey the client case sensitivity requests - only for clients that support it. */
63 if (lp_casesensitive(snum) == Auto) {
64 /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
65 enum remote_arch_types ra_type = get_remote_arch();
66 if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
67 /* Client can't support per-packet case sensitive pathnames. */
68 conn->case_sensitive = False;
69 } else {
70 conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
74 magic_char = lp_magicchar(snum);
75 return(True);
78 /****************************************************************************
79 Add a home service. Returns the new service number or -1 if fail.
80 ****************************************************************************/
82 int add_home_service(const char *service, const char *username, const char *homedir)
84 int iHomeService;
86 if (!service || !homedir)
87 return -1;
89 if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
90 return -1;
93 * If this is a winbindd provided username, remove
94 * the domain component before adding the service.
95 * Log a warning if the "path=" parameter does not
96 * include any macros.
100 const char *p = strchr(service,*lp_winbind_separator());
102 /* We only want the 'user' part of the string */
103 if (p) {
104 service = p + 1;
108 if (!lp_add_home(service, iHomeService, username, homedir)) {
109 return -1;
112 return lp_servicenumber(service);
118 * Find a service entry.
120 * @param service is modified (to canonical form??)
123 int find_service(fstring service)
125 int iService;
127 all_string_sub(service,"\\","/",0);
129 iService = lp_servicenumber(service);
131 /* now handle the special case of a home directory */
132 if (iService < 0) {
133 char *phome_dir = get_user_home_dir(service);
135 if(!phome_dir) {
137 * Try mapping the servicename, it may
138 * be a Windows to unix mapped user name.
140 if(map_username(service))
141 phome_dir = get_user_home_dir(service);
144 DEBUG(3,("checking for home directory %s gave %s\n",service,
145 phome_dir?phome_dir:"(NULL)"));
147 iService = add_home_service(service,service /* 'username' */, phome_dir);
150 /* If we still don't have a service, attempt to add it as a printer. */
151 if (iService < 0) {
152 int iPrinterService;
154 if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0) {
155 char *pszTemp;
157 DEBUG(3,("checking whether %s is a valid printer name...\n", service));
158 pszTemp = lp_printcapname();
159 if ((pszTemp != NULL) && pcap_printername_ok(service, pszTemp)) {
160 DEBUG(3,("%s is a valid printer name\n", service));
161 DEBUG(3,("adding %s as a printer service\n", service));
162 lp_add_printer(service, iPrinterService);
163 iService = lp_servicenumber(service);
164 if (iService < 0) {
165 DEBUG(0,("failed to add %s as a printer service!\n", service));
167 } else {
168 DEBUG(3,("%s is not a valid printer name\n", service));
173 /* Check for default vfs service? Unsure whether to implement this */
174 if (iService < 0) {
177 /* just possibly it's a default service? */
178 if (iService < 0) {
179 char *pdefservice = lp_defaultservice();
180 if (pdefservice && *pdefservice && !strequal(pdefservice,service) && !strstr_m(service,"..")) {
182 * We need to do a local copy here as lp_defaultservice()
183 * returns one of the rotating lp_string buffers that
184 * could get overwritten by the recursive find_service() call
185 * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
187 pstring defservice;
188 pstrcpy(defservice, pdefservice);
189 iService = find_service(defservice);
190 if (iService >= 0) {
191 all_string_sub(service, "_","/",0);
192 iService = lp_add_service(service, iService);
197 if (iService >= 0) {
198 if (!VALID_SNUM(iService)) {
199 DEBUG(0,("Invalid snum %d for %s\n",iService, service));
200 iService = -1;
204 if (iService < 0)
205 DEBUG(3,("find_service() failed to find service %s\n", service));
207 return (iService);
211 /****************************************************************************
212 do some basic sainity checks on the share.
213 This function modifies dev, ecode.
214 ****************************************************************************/
216 static NTSTATUS share_sanity_checks(int snum, fstring dev)
219 if (!lp_snum_ok(snum) ||
220 !check_access(smbd_server_fd(),
221 lp_hostsallow(snum), lp_hostsdeny(snum))) {
222 return NT_STATUS_ACCESS_DENIED;
225 if (dev[0] == '?' || !dev[0]) {
226 if (lp_print_ok(snum)) {
227 fstrcpy(dev,"LPT1:");
228 } else if (strequal(lp_fstype(snum), "IPC")) {
229 fstrcpy(dev, "IPC");
230 } else {
231 fstrcpy(dev,"A:");
235 strupper_m(dev);
237 if (lp_print_ok(snum)) {
238 if (!strequal(dev, "LPT1:")) {
239 return NT_STATUS_BAD_DEVICE_TYPE;
241 } else if (strequal(lp_fstype(snum), "IPC")) {
242 if (!strequal(dev, "IPC")) {
243 return NT_STATUS_BAD_DEVICE_TYPE;
245 } else if (!strequal(dev, "A:")) {
246 return NT_STATUS_BAD_DEVICE_TYPE;
249 /* Behave as a printer if we are supposed to */
250 if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
251 fstrcpy(dev, "LPT1:");
254 return NT_STATUS_OK;
257 /****************************************************************************
258 Make a connection, given the snum to connect to, and the vuser of the
259 connecting user if appropriate.
260 ****************************************************************************/
262 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
263 DATA_BLOB password,
264 const char *pdev, NTSTATUS *status)
266 struct passwd *pass = NULL;
267 BOOL guest = False;
268 connection_struct *conn;
269 struct stat st;
270 fstring user;
271 fstring dev;
273 *user = 0;
274 fstrcpy(dev, pdev);
276 if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
277 return NULL;
280 conn = conn_new();
281 if (!conn) {
282 DEBUG(0,("Couldn't find free connection.\n"));
283 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
284 return NULL;
287 if (lp_guest_only(snum)) {
288 const char *guestname = lp_guestaccount();
289 guest = True;
290 pass = getpwnam_alloc(guestname);
291 if (!pass) {
292 DEBUG(0,("make_connection_snum: Invalid guest account %s??\n",guestname));
293 conn_free(conn);
294 *status = NT_STATUS_NO_SUCH_USER;
295 return NULL;
297 fstrcpy(user,pass->pw_name);
298 conn->force_user = True;
299 conn->uid = pass->pw_uid;
300 conn->gid = pass->pw_gid;
301 string_set(&conn->user,pass->pw_name);
302 passwd_free(&pass);
303 DEBUG(3,("Guest only user %s\n",user));
304 } else if (vuser) {
305 if (vuser->guest) {
306 if (!lp_guest_ok(snum)) {
307 DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)\n", lp_servicename(snum)));
308 conn_free(conn);
309 *status = NT_STATUS_ACCESS_DENIED;
310 return NULL;
312 } else {
313 if (!user_ok(vuser->user.unix_name, snum, vuser->groups, vuser->n_groups)) {
314 DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)\n", vuser->user.unix_name, lp_servicename(snum)));
315 conn_free(conn);
316 *status = NT_STATUS_ACCESS_DENIED;
317 return NULL;
320 conn->vuid = vuser->vuid;
321 conn->uid = vuser->uid;
322 conn->gid = vuser->gid;
323 string_set(&conn->user,vuser->user.unix_name);
324 fstrcpy(user,vuser->user.unix_name);
325 guest = vuser->guest;
326 } else if (lp_security() == SEC_SHARE) {
327 /* add it as a possible user name if we
328 are in share mode security */
329 add_session_user(lp_servicename(snum));
330 /* shall we let them in? */
331 if (!authorise_login(snum,user,password,&guest)) {
332 DEBUG( 2, ( "Invalid username/password for [%s]\n",
333 lp_servicename(snum)) );
334 conn_free(conn);
335 *status = NT_STATUS_WRONG_PASSWORD;
336 return NULL;
338 pass = Get_Pwnam(user);
339 conn->force_user = True;
340 conn->uid = pass->pw_uid;
341 conn->gid = pass->pw_gid;
342 string_set(&conn->user, pass->pw_name);
343 fstrcpy(user, pass->pw_name);
345 } else {
346 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
347 conn_free(conn);
348 *status = NT_STATUS_ACCESS_DENIED;
349 return NULL;
352 add_session_user(user);
354 safe_strcpy(conn->client_address, client_addr(),
355 sizeof(conn->client_address)-1);
356 conn->num_files_open = 0;
357 conn->lastused = time(NULL);
358 conn->service = snum;
359 conn->used = True;
360 conn->printer = (strncmp(dev,"LPT",3) == 0);
361 conn->ipc = ((strncmp(dev,"IPC",3) == 0) || strequal(dev,"ADMIN$"));
362 conn->dirptr = NULL;
364 /* Case options for the share. */
365 if (lp_casesensitive(snum) == Auto) {
366 /* We will be setting this per packet. Set to be case insensitive for now. */
367 conn->case_sensitive = False;
368 } else {
369 conn->case_sensitive = (BOOL)lp_casesensitive(snum);
372 conn->case_preserve = lp_preservecase(snum);
373 conn->short_case_preserve = lp_shortpreservecase(snum);
375 conn->veto_list = NULL;
376 conn->hide_list = NULL;
377 conn->veto_oplock_list = NULL;
378 string_set(&conn->dirpath,"");
379 string_set(&conn->user,user);
380 conn->nt_user_token = NULL;
382 conn->read_only = lp_readonly(conn->service);
383 conn->admin_user = False;
386 * If force user is true, then store the
387 * given userid and also the groups
388 * of the user we're forcing.
391 if (*lp_force_user(snum)) {
392 struct passwd *pass2;
393 pstring fuser;
394 pstrcpy(fuser,lp_force_user(snum));
396 /* Allow %S to be used by force user. */
397 pstring_sub(fuser,"%S",lp_servicename(snum));
399 pass2 = (struct passwd *)Get_Pwnam(fuser);
400 if (pass2) {
401 conn->uid = pass2->pw_uid;
402 conn->gid = pass2->pw_gid;
403 string_set(&conn->user,pass2->pw_name);
404 fstrcpy(user,pass2->pw_name);
405 conn->force_user = True;
406 DEBUG(3,("Forced user %s\n",user));
407 } else {
408 DEBUG(1,("Couldn't find user %s\n",fuser));
409 conn_free(conn);
410 *status = NT_STATUS_NO_SUCH_USER;
411 return NULL;
415 #ifdef HAVE_GETGRNAM
417 * If force group is true, then override
418 * any groupid stored for the connecting user.
421 if (*lp_force_group(snum)) {
422 gid_t gid;
423 pstring gname;
424 pstring tmp_gname;
425 BOOL user_must_be_member = False;
427 pstrcpy(tmp_gname,lp_force_group(snum));
429 if (tmp_gname[0] == '+') {
430 user_must_be_member = True;
431 /* even now, tmp_gname is null terminated */
432 pstrcpy(gname,&tmp_gname[1]);
433 } else {
434 pstrcpy(gname,tmp_gname);
436 /* default service may be a group name */
437 pstring_sub(gname,"%S",lp_servicename(snum));
438 gid = nametogid(gname);
440 if (gid != (gid_t)-1) {
443 * If the user has been forced and the forced group starts
444 * with a '+', then we only set the group to be the forced
445 * group if the forced user is a member of that group.
446 * Otherwise, the meaning of the '+' would be ignored.
448 if (conn->force_user && user_must_be_member) {
449 if (user_in_group_list( user, gname, NULL, 0)) {
450 conn->gid = gid;
451 DEBUG(3,("Forced group %s for member %s\n",gname,user));
453 } else {
454 conn->gid = gid;
455 DEBUG(3,("Forced group %s\n",gname));
457 conn->force_group = True;
458 } else {
459 DEBUG(1,("Couldn't find group %s\n",gname));
460 conn_free(conn);
461 *status = NT_STATUS_NO_SUCH_GROUP;
462 return NULL;
465 #endif /* HAVE_GETGRNAM */
468 pstring s;
469 pstrcpy(s,lp_pathname(snum));
470 standard_sub_conn(conn,s,sizeof(s));
471 string_set(&conn->connectpath,s);
472 DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum)));
475 if (conn->force_user || conn->force_group) {
477 /* groups stuff added by ih */
478 conn->ngroups = 0;
479 conn->groups = NULL;
481 /* Find all the groups this uid is in and
482 store them. Used by change_to_user() */
483 initialise_groups(conn->user, conn->uid, conn->gid);
484 get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
486 conn->nt_user_token = create_nt_token(conn->uid, conn->gid,
487 conn->ngroups, conn->groups,
488 guest);
492 * New code to check if there's a share security descripter
493 * added from NT server manager. This is done after the
494 * smb.conf checks are done as we need a uid and token. JRA.
499 BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA);
501 if (!can_write) {
502 if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) {
503 /* No access, read or write. */
504 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
505 lp_servicename(snum)));
506 conn_free(conn);
507 *status = NT_STATUS_ACCESS_DENIED;
508 return NULL;
509 } else {
510 conn->read_only = True;
514 /* Initialise VFS function pointers */
516 if (!smbd_vfs_init(conn)) {
517 DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn))));
518 conn_free(conn);
519 *status = NT_STATUS_BAD_NETWORK_NAME;
520 return NULL;
524 * If widelinks are disallowed we need to canonicalise the
525 * connect path here to ensure we don't have any symlinks in
526 * the connectpath. We will be checking all paths on this
527 * connection are below this directory. We must do this after
528 * the VFS init as we depend on the realpath() pointer in the vfs table. JRA.
530 if (!lp_widelinks(snum)) {
531 pstring s;
532 pstrcpy(s,conn->connectpath);
533 canonicalize_path(conn, s);
534 string_set(&conn->connectpath,s);
537 /* ROOT Activities: */
538 /* check number of connections */
539 if (!claim_connection(conn,
540 lp_servicename(SNUM(conn)),
541 lp_max_connections(SNUM(conn)),
542 False,0)) {
543 DEBUG(1,("too many connections - rejected\n"));
544 conn_free(conn);
545 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
546 return NULL;
549 /* Preexecs are done here as they might make the dir we are to ChDir to below */
550 /* execute any "root preexec = " line */
551 if (*lp_rootpreexec(SNUM(conn))) {
552 int ret;
553 pstring cmd;
554 pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
555 standard_sub_conn(conn,cmd,sizeof(cmd));
556 DEBUG(5,("cmd=%s\n",cmd));
557 ret = smbrun(cmd,NULL);
558 if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
559 DEBUG(1,("root preexec gave %d - failing connection\n", ret));
560 yield_connection(conn, lp_servicename(SNUM(conn)));
561 conn_free(conn);
562 *status = NT_STATUS_ACCESS_DENIED;
563 return NULL;
567 /* USER Activites: */
568 if (!change_to_user(conn, conn->vuid)) {
569 /* No point continuing if they fail the basic checks */
570 DEBUG(0,("Can't become connected user!\n"));
571 conn_free(conn);
572 *status = NT_STATUS_LOGON_FAILURE;
573 return NULL;
576 /* Remember that a different vuid can connect later without these checks... */
578 /* Preexecs are done here as they might make the dir we are to ChDir to below */
579 /* execute any "preexec = " line */
580 if (*lp_preexec(SNUM(conn))) {
581 int ret;
582 pstring cmd;
583 pstrcpy(cmd,lp_preexec(SNUM(conn)));
584 standard_sub_conn(conn,cmd,sizeof(cmd));
585 ret = smbrun(cmd,NULL);
586 if (ret != 0 && lp_preexec_close(SNUM(conn))) {
587 DEBUG(1,("preexec gave %d - failing connection\n", ret));
588 change_to_root_user();
589 yield_connection(conn, lp_servicename(SNUM(conn)));
590 conn_free(conn);
591 *status = NT_STATUS_ACCESS_DENIED;
592 return NULL;
596 #ifdef WITH_FAKE_KASERVER
597 if (lp_afs_share(SNUM(conn))) {
598 afs_login(conn);
600 #endif
602 #if CHECK_PATH_ON_TCONX
603 /* win2000 does not check the permissions on the directory
604 during the tree connect, instead relying on permission
605 check during individual operations. To match this behaviour
606 I have disabled this chdir check (tridge) */
607 if (vfs_ChDir(conn,conn->connectpath) != 0) {
608 DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
609 get_remote_machine_name(), conn->client_address,
610 conn->connectpath,strerror(errno)));
611 change_to_root_user();
612 yield_connection(conn, lp_servicename(SNUM(conn)));
613 conn_free(conn);
614 *status = NT_STATUS_BAD_NETWORK_NAME;
615 return NULL;
617 #else
618 /* the alternative is just to check the directory exists */
619 if (stat(conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
620 DEBUG(0,("'%s' does not exist or is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(SNUM(conn))));
621 change_to_root_user();
622 yield_connection(conn, lp_servicename(SNUM(conn)));
623 conn_free(conn);
624 *status = NT_STATUS_BAD_NETWORK_NAME;
625 return NULL;
627 #endif
629 string_set(&conn->origpath,conn->connectpath);
631 #if SOFTLINK_OPTIMISATION
632 /* resolve any soft links early if possible */
633 if (vfs_ChDir(conn,conn->connectpath) == 0) {
634 pstring s;
635 pstrcpy(s,conn->connectpath);
636 vfs_GetWd(conn,s);
637 string_set(&conn->connectpath,s);
638 vfs_ChDir(conn,conn->connectpath);
640 #endif
643 * Print out the 'connected as' stuff here as we need
644 * to know the effective uid and gid we will be using
645 * (at least initially).
648 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
649 dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address );
650 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
651 dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
652 dbgtext( "initially as user %s ", user );
653 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
654 dbgtext( "(pid %d)\n", (int)sys_getpid() );
657 /* Add veto/hide lists */
658 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
659 set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
660 set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
661 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
664 /* Invoke VFS make connection hook */
666 if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
667 DEBUG(0,("make_connection: VFS make connection failed!\n"));
668 change_to_root_user();
669 conn_free(conn);
670 *status = NT_STATUS_UNSUCCESSFUL;
671 return NULL;
674 /* we've finished with the user stuff - go back to root */
675 change_to_root_user();
677 return(conn);
680 /***************************************************************************************
681 Simple wrapper function for make_connection() to include a call to
682 vfs_chdir()
683 **************************************************************************************/
685 connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password,
686 const char *dev, uint16 vuid, NTSTATUS *status)
688 connection_struct *conn = NULL;
690 conn = make_connection(service_in, password, dev, vuid, status);
693 * make_connection() does not change the directory for us any more
694 * so we have to do it as a separate step --jerry
697 if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
698 DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n",
699 conn->connectpath,strerror(errno)));
700 yield_connection(conn, lp_servicename(SNUM(conn)));
701 conn_free(conn);
702 *status = NT_STATUS_UNSUCCESSFUL;
703 return NULL;
706 return conn;
709 /****************************************************************************
710 Make a connection to a service.
712 * @param service
713 ****************************************************************************/
715 connection_struct *make_connection(const char *service_in, DATA_BLOB password,
716 const char *pdev, uint16 vuid, NTSTATUS *status)
718 uid_t euid;
719 user_struct *vuser = NULL;
720 fstring service;
721 fstring dev;
722 int snum = -1;
724 fstrcpy(dev, pdev);
726 /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
727 if (!non_root_mode() && (euid = geteuid()) != 0) {
728 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
729 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
732 if(lp_security() != SEC_SHARE) {
733 vuser = get_valid_user_struct(vuid);
734 if (!vuser) {
735 DEBUG(1,("make_connection: refusing to connect with no session setup\n"));
736 *status = NT_STATUS_ACCESS_DENIED;
737 return NULL;
741 /* Logic to try and connect to the correct [homes] share, preferably without too many
742 getpwnam() lookups. This is particulary nasty for winbind usernames, where the
743 share name isn't the same as unix username.
745 The snum of the homes share is stored on the vuser at session setup time.
748 if (strequal(service_in,HOMES_NAME)) {
749 if(lp_security() != SEC_SHARE) {
750 DATA_BLOB no_pw = data_blob(NULL, 0);
751 if (vuser->homes_snum == -1) {
752 DEBUG(2, ("[homes] share not available for this user because it was not found or created at session setup time\n"));
753 *status = NT_STATUS_BAD_NETWORK_NAME;
754 return NULL;
756 DEBUG(5, ("making a connection to [homes] service created at session setup time\n"));
757 return make_connection_snum(vuser->homes_snum,
758 vuser, no_pw,
759 dev, status);
760 } else {
761 /* Security = share. Try with current_user_info.smb_name
762 * as the username. */
763 if (*current_user_info.smb_name) {
764 fstring unix_username;
765 fstrcpy(unix_username,
766 current_user_info.smb_name);
767 map_username(unix_username);
768 snum = find_service(unix_username);
770 if (snum != -1) {
771 DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in));
772 return make_connection_snum(snum, NULL,
773 password,
774 dev, status);
777 } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
778 && strequal(service_in, lp_servicename(vuser->homes_snum))) {
779 DATA_BLOB no_pw = data_blob(NULL, 0);
780 DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service_in));
781 return make_connection_snum(vuser->homes_snum,
782 vuser, no_pw,
783 dev, status);
786 fstrcpy(service, service_in);
788 strlower_m(service);
790 snum = find_service(service);
792 if (snum < 0) {
793 if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
794 DEBUG(3,("refusing IPC connection to %s\n", service));
795 *status = NT_STATUS_ACCESS_DENIED;
796 return NULL;
799 DEBUG(0,("%s (%s) couldn't find service %s\n",
800 get_remote_machine_name(), client_addr(), service));
801 *status = NT_STATUS_BAD_NETWORK_NAME;
802 return NULL;
805 /* Handle non-Dfs clients attempting connections to msdfs proxy */
806 if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) {
807 DEBUG(3, ("refusing connection to dfs proxy '%s'\n", service));
808 *status = NT_STATUS_BAD_NETWORK_NAME;
809 return NULL;
812 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
814 return make_connection_snum(snum, vuser,
815 password,
816 dev, status);
819 /****************************************************************************
820 close a cnum
821 ****************************************************************************/
822 void close_cnum(connection_struct *conn, uint16 vuid)
824 DirCacheFlush(SNUM(conn));
826 if (IS_IPC(conn)) {
827 pipe_close_conn(conn);
828 } else {
829 file_close_conn(conn);
830 dptr_closecnum(conn);
833 change_to_root_user();
835 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
836 get_remote_machine_name(),conn->client_address,
837 lp_servicename(SNUM(conn))));
839 /* Call VFS disconnect hook */
840 SMB_VFS_DISCONNECT(conn);
842 yield_connection(conn, lp_servicename(SNUM(conn)));
844 /* make sure we leave the directory available for unmount */
845 vfs_ChDir(conn, "/");
847 /* execute any "postexec = " line */
848 if (*lp_postexec(SNUM(conn)) &&
849 change_to_user(conn, vuid)) {
850 pstring cmd;
851 pstrcpy(cmd,lp_postexec(SNUM(conn)));
852 standard_sub_conn(conn,cmd,sizeof(cmd));
853 smbrun(cmd,NULL);
854 change_to_root_user();
857 change_to_root_user();
858 /* execute any "root postexec = " line */
859 if (*lp_rootpostexec(SNUM(conn))) {
860 pstring cmd;
861 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
862 standard_sub_conn(conn,cmd,sizeof(cmd));
863 smbrun(cmd,NULL);
866 conn_free(conn);
869 /****************************************************************************
870 Remove stale printers
871 ****************************************************************************/
873 void remove_stale_printers( void )
875 int snum, iNumServices, printersServiceNum;
876 const char *pname;
878 iNumServices = lp_numservices();
879 printersServiceNum = lp_servicenumber( PRINTERS_NAME);
880 for( snum = 0; snum < iNumServices; snum++) {
881 /* Never remove PRINTERS_NAME */
882 if ( snum == printersServiceNum)
883 continue;
884 pname = lp_printername( snum);
885 /* Is snum a print service and still in the printing subsystem? */
886 if ( lp_print_ok( snum) && !pcap_printername_ok( pname, NULL)) {
887 DEBUG( 3, ( "Removing printer: %s\n", pname));
888 lp_killservice( snum);