cleaning out patch list; patch from Steve L. to change the cwd before the postexec...
[Samba.git] / source / smbd / service.c
blobe5655bd9f4c23498016ee6191e637b5c2b2ff31a
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 int case_default;
25 extern BOOL case_preserve;
26 extern BOOL short_case_preserve;
27 extern BOOL case_mangle;
28 extern BOOL case_sensitive;
29 extern BOOL use_mangled_map;
30 extern userdom_struct current_user_info;
33 /****************************************************************************
34 Load parameters specific to a connection/service.
35 ****************************************************************************/
37 BOOL set_current_service(connection_struct *conn,BOOL do_chdir)
39 extern char magic_char;
40 static connection_struct *last_conn;
41 int snum;
43 if (!conn) {
44 last_conn = NULL;
45 return(False);
48 conn->lastused = smb_last_time.tv_sec;
50 snum = SNUM(conn);
52 if (do_chdir &&
53 vfs_ChDir(conn,conn->connectpath) != 0 &&
54 vfs_ChDir(conn,conn->origpath) != 0) {
55 DEBUG(0,("chdir (%s) failed\n",
56 conn->connectpath));
57 return(False);
60 if (conn == last_conn)
61 return(True);
63 last_conn = conn;
65 case_default = lp_defaultcase(snum);
66 case_preserve = lp_preservecase(snum);
67 short_case_preserve = lp_shortpreservecase(snum);
68 case_mangle = lp_casemangle(snum);
69 case_sensitive = lp_casesensitive(snum);
70 magic_char = lp_magicchar(snum);
71 use_mangled_map = (*lp_mangled_map(snum) ? True:False);
72 return(True);
75 /****************************************************************************
76 Add a home service. Returns the new service number or -1 if fail.
77 ****************************************************************************/
79 int add_home_service(const char *service, const char *username, const char *homedir)
81 int iHomeService;
83 if (!service || !homedir)
84 return -1;
86 if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
87 return -1;
90 * If this is a winbindd provided username, remove
91 * the domain component before adding the service.
92 * Log a warning if the "path=" parameter does not
93 * include any macros.
97 const char *p = strchr(service,*lp_winbind_separator());
99 /* We only want the 'user' part of the string */
100 if (p) {
101 service = p + 1;
105 if (!lp_add_home(service, iHomeService, username, homedir)) {
106 return -1;
109 return lp_servicenumber(service);
115 * Find a service entry. service is always in dos codepage.
117 * @param service is modified (to canonical form??)
119 int find_service(fstring service)
121 int iService;
123 all_string_sub(service,"\\","/",0);
125 iService = lp_servicenumber(service);
127 /* now handle the special case of a home directory */
128 if (iService < 0)
130 char *phome_dir = get_user_home_dir(service);
132 if(!phome_dir)
135 * Try mapping the servicename, it may
136 * be a Windows to unix mapped user name.
138 if(map_username(service))
139 phome_dir = get_user_home_dir(service);
142 DEBUG(3,("checking for home directory %s gave %s\n",service,
143 phome_dir?phome_dir:"(NULL)"));
145 iService = add_home_service(service,service /* 'username' */, phome_dir);
148 /* If we still don't have a service, attempt to add it as a printer. */
149 if (iService < 0)
151 int iPrinterService;
153 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))
161 DEBUG(3,("%s is a valid printer name\n", service));
162 DEBUG(3,("adding %s as a printer service\n", service));
163 lp_add_printer(service, iPrinterService);
164 iService = lp_servicenumber(service);
165 if (iService < 0)
166 DEBUG(0,("failed to add %s as a printer service!\n", service));
168 else
169 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)
178 /* just possibly it's a default service? */
179 if (iService < 0)
181 char *pdefservice = lp_defaultservice();
182 if (pdefservice && *pdefservice &&
183 !strequal(pdefservice,service) &&
184 !strstr(service,".."))
187 * We need to do a local copy here as lp_defaultservice()
188 * returns one of the rotating lp_string buffers that
189 * could get overwritten by the recursive find_service() call
190 * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
192 pstring defservice;
193 pstrcpy(defservice, pdefservice);
194 iService = find_service(defservice);
195 if (iService >= 0)
197 all_string_sub(service, "_","/",0);
198 iService = lp_add_service(service, iService);
203 if (iService >= 0)
204 if (!VALID_SNUM(iService))
206 DEBUG(0,("Invalid snum %d for %s\n",iService, service));
207 iService = -1;
210 if (iService < 0)
211 DEBUG(3,("find_service() failed to find service %s\n", service));
213 return (iService);
217 /****************************************************************************
218 do some basic sainity checks on the share.
219 This function modifies dev, ecode.
220 ****************************************************************************/
221 static NTSTATUS share_sanity_checks(int snum, fstring dev)
224 if (!lp_snum_ok(snum) ||
225 !check_access(smbd_server_fd(),
226 lp_hostsallow(snum), lp_hostsdeny(snum))) {
227 return NT_STATUS_ACCESS_DENIED;
230 if (dev[0] == '?' || !dev[0]) {
231 if (lp_print_ok(snum)) {
232 fstrcpy(dev,"LPT1:");
233 } else if (strequal(lp_fstype(snum), "IPC")) {
234 fstrcpy(dev, "IPC");
235 } else {
236 fstrcpy(dev,"A:");
240 strupper_m(dev);
242 if (lp_print_ok(snum)) {
243 if (!strequal(dev, "LPT1:")) {
244 return NT_STATUS_BAD_DEVICE_TYPE;
246 } else if (strequal(lp_fstype(snum), "IPC")) {
247 if (!strequal(dev, "IPC")) {
248 return NT_STATUS_BAD_DEVICE_TYPE;
250 } else if (!strequal(dev, "A:")) {
251 return NT_STATUS_BAD_DEVICE_TYPE;
254 /* Behave as a printer if we are supposed to */
255 if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
256 fstrcpy(dev, "LPT1:");
259 return NT_STATUS_OK;
262 /****************************************************************************
263 readonly share?
264 ****************************************************************************/
266 static void set_read_only(connection_struct *conn, gid_t *groups, size_t n_groups)
268 char **list;
269 const char *service = lp_servicename(conn->service);
270 conn->read_only = lp_readonly(conn->service);
272 if (!service)
273 return;
275 str_list_copy(&list, lp_readlist(conn->service));
276 if (list) {
277 if (!str_list_sub_basic(list, current_user_info.smb_name) ) {
278 DEBUG(0, ("ERROR: read list substitution failed\n"));
280 if (!str_list_substitute(list, "%S", service)) {
281 DEBUG(0, ("ERROR: read list service substitution failed\n"));
283 if (user_in_list(conn->user, (const char **)list, groups, n_groups))
284 conn->read_only = True;
285 str_list_free(&list);
288 str_list_copy(&list, lp_writelist(conn->service));
289 if (list) {
290 if (!str_list_sub_basic(list, current_user_info.smb_name) ) {
291 DEBUG(0, ("ERROR: write list substitution failed\n"));
293 if (!str_list_substitute(list, "%S", service)) {
294 DEBUG(0, ("ERROR: write list service substitution failed\n"));
296 if (user_in_list(conn->user, (const char **)list, groups, n_groups))
297 conn->read_only = False;
298 str_list_free(&list);
302 /****************************************************************************
303 admin user check
304 ****************************************************************************/
306 static void set_admin_user(connection_struct *conn, gid_t *groups, size_t n_groups)
308 /* admin user check */
310 /* JRA - original code denied admin user if the share was
311 marked read_only. Changed as I don't think this is needed,
312 but old code left in case there is a problem here.
314 if (user_in_list(conn->user,lp_admin_users(conn->service), groups, n_groups)
315 #if 0
316 && !conn->read_only
317 #endif
319 conn->admin_user = True;
320 conn->force_user = True; /* Admin users are effectivly 'forced' */
321 DEBUG(0,("%s logged in as admin user (root privileges)\n",conn->user));
322 } else {
323 conn->admin_user = False;
326 #if 0 /* This done later, for now */
327 /* admin users always run as uid=0 */
328 if (conn->admin_user) {
329 conn->uid = 0;
331 #endif
334 /****************************************************************************
335 Make a connection, given the snum to connect to, and the vuser of the
336 connecting user if appropriate.
337 ****************************************************************************/
339 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
340 DATA_BLOB password,
341 const char *pdev, NTSTATUS *status)
343 struct passwd *pass = NULL;
344 BOOL guest = False;
345 connection_struct *conn;
346 struct stat st;
347 fstring user;
348 fstring dev;
350 *user = 0;
351 fstrcpy(dev, pdev);
353 if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
354 return NULL;
357 conn = conn_new();
358 if (!conn) {
359 DEBUG(0,("Couldn't find free connection.\n"));
360 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
361 return NULL;
364 if (lp_guest_only(snum)) {
365 const char *guestname = lp_guestaccount();
366 guest = True;
367 pass = getpwnam_alloc(guestname);
368 if (!pass) {
369 DEBUG(0,("make_connection_snum: Invalid guest account %s??\n",guestname));
370 conn_free(conn);
371 *status = NT_STATUS_NO_SUCH_USER;
372 return NULL;
374 fstrcpy(user,pass->pw_name);
375 conn->force_user = True;
376 conn->uid = pass->pw_uid;
377 conn->gid = pass->pw_gid;
378 string_set(&conn->user,pass->pw_name);
379 passwd_free(&pass);
380 DEBUG(3,("Guest only user %s\n",user));
381 } else if (vuser) {
382 if (vuser->guest) {
383 if (!lp_guest_ok(snum)) {
384 DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)\n", lp_servicename(snum)));
385 conn_free(conn);
386 *status = NT_STATUS_ACCESS_DENIED;
387 return NULL;
389 } else {
390 if (!user_ok(vuser->user.unix_name, snum, vuser->groups, vuser->n_groups)) {
391 DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)\n", vuser->user.unix_name, lp_servicename(snum)));
392 conn_free(conn);
393 *status = NT_STATUS_ACCESS_DENIED;
394 return NULL;
397 conn->vuid = vuser->vuid;
398 conn->uid = vuser->uid;
399 conn->gid = vuser->gid;
400 string_set(&conn->user,vuser->user.unix_name);
401 fstrcpy(user,vuser->user.unix_name);
402 guest = vuser->guest;
403 } else if (lp_security() == SEC_SHARE) {
404 /* add it as a possible user name if we
405 are in share mode security */
406 add_session_user(lp_servicename(snum));
407 /* shall we let them in? */
408 if (!authorise_login(snum,user,password,&guest)) {
409 DEBUG( 2, ( "Invalid username/password for [%s]\n",
410 lp_servicename(snum)) );
411 conn_free(conn);
412 *status = NT_STATUS_WRONG_PASSWORD;
413 return NULL;
415 pass = Get_Pwnam(user);
416 conn->force_user = True;
417 conn->uid = pass->pw_uid;
418 conn->gid = pass->pw_gid;
419 string_set(&conn->user, pass->pw_name);
420 fstrcpy(user, pass->pw_name);
422 } else {
423 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
424 conn_free(conn);
425 *status = NT_STATUS_ACCESS_DENIED;
426 return NULL;
429 add_session_user(user);
431 safe_strcpy(conn->client_address, client_addr(),
432 sizeof(conn->client_address)-1);
433 conn->num_files_open = 0;
434 conn->lastused = time(NULL);
435 conn->service = snum;
436 conn->used = True;
437 conn->printer = (strncmp(dev,"LPT",3) == 0);
438 conn->ipc = ((strncmp(dev,"IPC",3) == 0) || strequal(dev,"ADMIN$"));
439 conn->dirptr = NULL;
440 conn->veto_list = NULL;
441 conn->hide_list = NULL;
442 conn->veto_oplock_list = NULL;
443 string_set(&conn->dirpath,"");
444 string_set(&conn->user,user);
445 conn->nt_user_token = NULL;
447 set_read_only(conn, vuser ? vuser->groups : NULL, vuser ? vuser->n_groups : 0);
449 set_admin_user(conn, vuser ? vuser->groups : NULL, vuser ? vuser->n_groups : 0);
452 * If force user is true, then store the
453 * given userid and also the groups
454 * of the user we're forcing.
457 if (*lp_force_user(snum)) {
458 struct passwd *pass2;
459 pstring fuser;
460 pstrcpy(fuser,lp_force_user(snum));
462 /* Allow %S to be used by force user. */
463 pstring_sub(fuser,"%S",lp_servicename(snum));
465 pass2 = (struct passwd *)Get_Pwnam(fuser);
466 if (pass2) {
467 conn->uid = pass2->pw_uid;
468 conn->gid = pass2->pw_gid;
469 string_set(&conn->user,pass2->pw_name);
470 fstrcpy(user,pass2->pw_name);
471 conn->force_user = True;
472 DEBUG(3,("Forced user %s\n",user));
473 } else {
474 DEBUG(1,("Couldn't find user %s\n",fuser));
475 conn_free(conn);
476 *status = NT_STATUS_NO_SUCH_USER;
477 return NULL;
481 /* admin users always run as uid=0 */
482 if (conn->admin_user) {
483 conn->uid = 0;
486 #ifdef HAVE_GETGRNAM
488 * If force group is true, then override
489 * any groupid stored for the connecting user.
492 if (*lp_force_group(snum)) {
493 gid_t gid;
494 pstring gname;
495 pstring tmp_gname;
496 BOOL user_must_be_member = False;
498 pstrcpy(tmp_gname,lp_force_group(snum));
500 if (tmp_gname[0] == '+') {
501 user_must_be_member = True;
502 /* even now, tmp_gname is null terminated */
503 pstrcpy(gname,&tmp_gname[1]);
504 } else {
505 pstrcpy(gname,tmp_gname);
507 /* default service may be a group name */
508 pstring_sub(gname,"%S",lp_servicename(snum));
509 gid = nametogid(gname);
511 if (gid != (gid_t)-1) {
514 * If the user has been forced and the forced group starts
515 * with a '+', then we only set the group to be the forced
516 * group if the forced user is a member of that group.
517 * Otherwise, the meaning of the '+' would be ignored.
519 if (conn->force_user && user_must_be_member) {
520 if (user_in_group_list( user, gname, NULL, 0)) {
521 conn->gid = gid;
522 DEBUG(3,("Forced group %s for member %s\n",gname,user));
524 } else {
525 conn->gid = gid;
526 DEBUG(3,("Forced group %s\n",gname));
528 conn->force_group = True;
529 } else {
530 DEBUG(1,("Couldn't find group %s\n",gname));
531 conn_free(conn);
532 *status = NT_STATUS_NO_SUCH_GROUP;
533 return NULL;
536 #endif /* HAVE_GETGRNAM */
539 pstring s;
540 pstrcpy(s,lp_pathname(snum));
541 standard_sub_conn(conn,s,sizeof(s));
542 string_set(&conn->connectpath,s);
543 DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum)));
546 if (conn->force_user || conn->force_group) {
548 /* groups stuff added by ih */
549 conn->ngroups = 0;
550 conn->groups = NULL;
552 /* Find all the groups this uid is in and
553 store them. Used by change_to_user() */
554 initialise_groups(conn->user, conn->uid, conn->gid);
555 get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
557 conn->nt_user_token = create_nt_token(conn->uid, conn->gid,
558 conn->ngroups, conn->groups,
559 guest);
563 * New code to check if there's a share security descripter
564 * added from NT server manager. This is done after the
565 * smb.conf checks are done as we need a uid and token. JRA.
570 BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA);
572 if (!can_write) {
573 if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) {
574 /* No access, read or write. */
575 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
576 lp_servicename(snum)));
577 conn_free(conn);
578 *status = NT_STATUS_ACCESS_DENIED;
579 return NULL;
580 } else {
581 conn->read_only = True;
585 /* Initialise VFS function pointers */
587 if (!smbd_vfs_init(conn)) {
588 DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn))));
589 conn_free(conn);
590 *status = NT_STATUS_BAD_NETWORK_NAME;
591 return NULL;
594 /* ROOT Activities: */
595 /* check number of connections */
596 if (!claim_connection(conn,
597 lp_servicename(SNUM(conn)),
598 lp_max_connections(SNUM(conn)),
599 False,0)) {
600 DEBUG(1,("too many connections - rejected\n"));
601 conn_free(conn);
602 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
603 return NULL;
606 /* Preexecs are done here as they might make the dir we are to ChDir to below */
607 /* execute any "root preexec = " line */
608 if (*lp_rootpreexec(SNUM(conn))) {
609 int ret;
610 pstring cmd;
611 pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
612 standard_sub_conn(conn,cmd,sizeof(cmd));
613 DEBUG(5,("cmd=%s\n",cmd));
614 ret = smbrun(cmd,NULL);
615 if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
616 DEBUG(1,("root preexec gave %d - failing connection\n", ret));
617 yield_connection(conn, lp_servicename(SNUM(conn)));
618 conn_free(conn);
619 *status = NT_STATUS_ACCESS_DENIED;
620 return NULL;
624 /* USER Activites: */
625 if (!change_to_user(conn, conn->vuid)) {
626 /* No point continuing if they fail the basic checks */
627 DEBUG(0,("Can't become connected user!\n"));
628 conn_free(conn);
629 *status = NT_STATUS_LOGON_FAILURE;
630 return NULL;
633 /* Remember that a different vuid can connect later without these checks... */
635 /* Preexecs are done here as they might make the dir we are to ChDir to below */
636 /* execute any "preexec = " line */
637 if (*lp_preexec(SNUM(conn))) {
638 int ret;
639 pstring cmd;
640 pstrcpy(cmd,lp_preexec(SNUM(conn)));
641 standard_sub_conn(conn,cmd,sizeof(cmd));
642 ret = smbrun(cmd,NULL);
643 if (ret != 0 && lp_preexec_close(SNUM(conn))) {
644 DEBUG(1,("preexec gave %d - failing connection\n", ret));
645 change_to_root_user();
646 yield_connection(conn, lp_servicename(SNUM(conn)));
647 conn_free(conn);
648 *status = NT_STATUS_ACCESS_DENIED;
649 return NULL;
653 #ifdef WITH_FAKE_KASERVER
654 if (lp_afs_share(SNUM(conn))) {
655 afs_login(conn);
657 #endif
659 #if CHECK_PATH_ON_TCONX
660 /* win2000 does not check the permissions on the directory
661 during the tree connect, instead relying on permission
662 check during individual operations. To match this behaviour
663 I have disabled this chdir check (tridge) */
664 if (vfs_ChDir(conn,conn->connectpath) != 0) {
665 DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
666 get_remote_machine_name(), conn->client_address,
667 conn->connectpath,strerror(errno)));
668 change_to_root_user();
669 yield_connection(conn, lp_servicename(SNUM(conn)));
670 conn_free(conn);
671 *status = NT_STATUS_BAD_NETWORK_NAME;
672 return NULL;
674 #else
675 /* the alternative is just to check the directory exists */
676 if (stat(conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
677 DEBUG(0,("'%s' does not exist or is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(SNUM(conn))));
678 change_to_root_user();
679 yield_connection(conn, lp_servicename(SNUM(conn)));
680 conn_free(conn);
681 *status = NT_STATUS_BAD_NETWORK_NAME;
682 return NULL;
684 #endif
686 string_set(&conn->origpath,conn->connectpath);
688 #if SOFTLINK_OPTIMISATION
689 /* resolve any soft links early if possible */
690 if (vfs_ChDir(conn,conn->connectpath) == 0) {
691 pstring s;
692 pstrcpy(s,conn->connectpath);
693 vfs_GetWd(conn,s);
694 string_set(&conn->connectpath,s);
695 vfs_ChDir(conn,conn->connectpath);
697 #endif
700 * Print out the 'connected as' stuff here as we need
701 * to know the effective uid and gid we will be using
702 * (at least initially).
705 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
706 dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address );
707 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
708 dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
709 dbgtext( "initially as user %s ", user );
710 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
711 dbgtext( "(pid %d)\n", (int)sys_getpid() );
714 /* Add veto/hide lists */
715 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
716 set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
717 set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
718 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
721 /* Invoke VFS make connection hook */
723 if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
724 DEBUG(0,("make_connection: VFS make connection failed!\n"));
725 change_to_root_user();
726 conn_free(conn);
727 *status = NT_STATUS_UNSUCCESSFUL;
728 return NULL;
731 /* we've finished with the user stuff - go back to root */
732 change_to_root_user();
734 return(conn);
737 /***************************************************************************************
738 Simple wrapper function for make_connection() to include a call to
739 vfs_chdir()
740 **************************************************************************************/
742 connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password,
743 const char *dev, uint16 vuid, NTSTATUS *status)
745 connection_struct *conn = NULL;
747 conn = make_connection(service_in, password, dev, vuid, status);
750 * make_connection() does not change the directory for us any more
751 * so we have to do it as a separate step --jerry
754 if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
755 DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n",
756 conn->connectpath,strerror(errno)));
757 yield_connection(conn, lp_servicename(SNUM(conn)));
758 conn_free(conn);
759 *status = NT_STATUS_UNSUCCESSFUL;
760 return NULL;
763 return conn;
766 /****************************************************************************
767 Make a connection to a service.
769 * @param service
770 ****************************************************************************/
772 connection_struct *make_connection(const char *service_in, DATA_BLOB password,
773 const char *pdev, uint16 vuid, NTSTATUS *status)
775 uid_t euid;
776 user_struct *vuser = NULL;
777 fstring service;
778 fstring dev;
779 int snum = -1;
781 fstrcpy(dev, pdev);
783 /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
784 if (!non_root_mode() && (euid = geteuid()) != 0) {
785 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
786 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
789 if(lp_security() != SEC_SHARE) {
790 vuser = get_valid_user_struct(vuid);
791 if (!vuser) {
792 DEBUG(1,("make_connection: refusing to connect with no session setup\n"));
793 *status = NT_STATUS_ACCESS_DENIED;
794 return NULL;
798 /* Logic to try and connect to the correct [homes] share, preferably without too many
799 getpwnam() lookups. This is particulary nasty for winbind usernames, where the
800 share name isn't the same as unix username.
802 The snum of the homes share is stored on the vuser at session setup time.
805 if (strequal(service_in,HOMES_NAME)) {
806 if(lp_security() != SEC_SHARE) {
807 DATA_BLOB no_pw = data_blob(NULL, 0);
808 if (vuser->homes_snum == -1) {
809 DEBUG(2, ("[homes] share not available for this user because it was not found or created at session setup time\n"));
810 *status = NT_STATUS_BAD_NETWORK_NAME;
811 return NULL;
813 DEBUG(5, ("making a connection to [homes] service created at session setup time\n"));
814 return make_connection_snum(vuser->homes_snum,
815 vuser, no_pw,
816 dev, status);
817 } else {
818 /* Security = share. Try with current_user_info.smb_name
819 * as the username. */
820 if (*current_user_info.smb_name) {
821 fstring unix_username;
822 fstrcpy(unix_username,
823 current_user_info.smb_name);
824 map_username(unix_username);
825 snum = find_service(unix_username);
827 if (snum != -1) {
828 DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in));
829 return make_connection_snum(snum, NULL,
830 password,
831 dev, status);
834 } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
835 && strequal(service_in, lp_servicename(vuser->homes_snum))) {
836 DATA_BLOB no_pw = data_blob(NULL, 0);
837 DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service_in));
838 return make_connection_snum(vuser->homes_snum,
839 vuser, no_pw,
840 dev, status);
843 fstrcpy(service, service_in);
845 strlower_m(service);
847 snum = find_service(service);
849 if (snum < 0) {
850 if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
851 DEBUG(3,("refusing IPC connection to %s\n", service));
852 *status = NT_STATUS_ACCESS_DENIED;
853 return NULL;
856 DEBUG(0,("%s (%s) couldn't find service %s\n",
857 get_remote_machine_name(), client_addr(), service));
858 *status = NT_STATUS_BAD_NETWORK_NAME;
859 return NULL;
862 /* Handle non-Dfs clients attempting connections to msdfs proxy */
863 if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) {
864 DEBUG(3, ("refusing connection to dfs proxy '%s'\n", service));
865 *status = NT_STATUS_BAD_NETWORK_NAME;
866 return NULL;
869 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
871 return make_connection_snum(snum, vuser,
872 password,
873 dev, status);
876 /****************************************************************************
877 close a cnum
878 ****************************************************************************/
879 void close_cnum(connection_struct *conn, uint16 vuid)
881 DirCacheFlush(SNUM(conn));
883 change_to_root_user();
885 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
886 get_remote_machine_name(),conn->client_address,
887 lp_servicename(SNUM(conn))));
889 /* Call VFS disconnect hook */
890 SMB_VFS_DISCONNECT(conn);
892 yield_connection(conn, lp_servicename(SNUM(conn)));
894 file_close_conn(conn);
895 dptr_closecnum(conn);
897 /* make sure we leave the directory available for unmount */
898 vfs_ChDir(conn, "/");
900 /* execute any "postexec = " line */
901 if (*lp_postexec(SNUM(conn)) &&
902 change_to_user(conn, vuid)) {
903 pstring cmd;
904 pstrcpy(cmd,lp_postexec(SNUM(conn)));
905 standard_sub_conn(conn,cmd,sizeof(cmd));
906 smbrun(cmd,NULL);
907 change_to_root_user();
910 change_to_root_user();
911 /* execute any "root postexec = " line */
912 if (*lp_rootpostexec(SNUM(conn))) {
913 pstring cmd;
914 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
915 standard_sub_conn(conn,cmd,sizeof(cmd));
916 smbrun(cmd,NULL);
919 conn_free(conn);