This only touches the fake kaserver support. It adds two parameters:
[Samba/gebeck_regimport.git] / source3 / smbd / service.c
blob44d73b2ab27b8382c4994969dc60c8508f0ebd1b
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;
263 /****************************************************************************
264 readonly share?
265 ****************************************************************************/
266 static void set_read_only(connection_struct *conn, gid_t *groups, size_t n_groups)
268 char **list;
269 char *service = lp_servicename(conn->service);
270 conn->read_only = lp_readonly(conn->service);
272 if (!service) return;
274 str_list_copy(&list, lp_readlist(conn->service));
275 if (list) {
276 if ( !str_list_sub_basic(list, current_user_info.smb_name) ) {
277 DEBUG(0, ("ERROR: read list substitution failed\n"));
279 if (user_in_list(conn->user, (const char **)list, groups, n_groups))
280 conn->read_only = True;
281 str_list_free(&list);
284 str_list_copy(&list, lp_writelist(conn->service));
285 if (list) {
286 if ( !str_list_sub_basic(list, current_user_info.smb_name) ) {
287 DEBUG(0, ("ERROR: write list substitution failed\n"));
289 if (user_in_list(conn->user, (const char **)list, groups, n_groups))
290 conn->read_only = False;
291 str_list_free(&list);
296 /****************************************************************************
297 admin user check
298 ****************************************************************************/
299 static void set_admin_user(connection_struct *conn, gid_t *groups, size_t n_groups)
301 /* admin user check */
303 /* JRA - original code denied admin user if the share was
304 marked read_only. Changed as I don't think this is needed,
305 but old code left in case there is a problem here.
307 if (user_in_list(conn->user,lp_admin_users(conn->service), groups, n_groups)
308 #if 0
309 && !conn->read_only
310 #endif
312 conn->admin_user = True;
313 conn->force_user = True; /* Admin users are effectivly 'forced' */
314 DEBUG(0,("%s logged in as admin user (root privileges)\n",conn->user));
315 } else {
316 conn->admin_user = False;
319 #if 0 /* This done later, for now */
320 /* admin users always run as uid=0 */
321 if (conn->admin_user) {
322 conn->uid = 0;
324 #endif
327 /****************************************************************************
328 Make a connection, given the snum to connect to, and the vuser of the
329 connecting user if appropriate.
330 ****************************************************************************/
332 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
333 DATA_BLOB password,
334 const char *pdev, NTSTATUS *status)
336 struct passwd *pass = NULL;
337 BOOL guest = False;
338 connection_struct *conn;
339 struct stat st;
340 fstring user;
341 fstring dev;
343 *user = 0;
344 fstrcpy(dev, pdev);
346 if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
347 return NULL;
350 conn = conn_new();
351 if (!conn) {
352 DEBUG(0,("Couldn't find free connection.\n"));
353 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
354 return NULL;
357 if (lp_guest_only(snum)) {
358 const char *guestname = lp_guestaccount();
359 guest = True;
360 pass = getpwnam_alloc(guestname);
361 if (!pass) {
362 DEBUG(0,("make_connection_snum: Invalid guest account %s??\n",guestname));
363 conn_free(conn);
364 *status = NT_STATUS_NO_SUCH_USER;
365 return NULL;
367 fstrcpy(user,pass->pw_name);
368 conn->force_user = True;
369 conn->uid = pass->pw_uid;
370 conn->gid = pass->pw_gid;
371 string_set(&conn->user,pass->pw_name);
372 passwd_free(&pass);
373 DEBUG(3,("Guest only user %s\n",user));
374 } else if (vuser) {
375 if (vuser->guest) {
376 if (!lp_guest_ok(snum)) {
377 DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)\n", lp_servicename(snum)));
378 conn_free(conn);
379 *status = NT_STATUS_ACCESS_DENIED;
380 return NULL;
382 } else {
383 if (!user_ok(vuser->user.unix_name, snum, vuser->groups, vuser->n_groups)) {
384 DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)\n", vuser->user.unix_name, lp_servicename(snum)));
385 conn_free(conn);
386 *status = NT_STATUS_ACCESS_DENIED;
387 return NULL;
390 conn->vuid = vuser->vuid;
391 conn->uid = vuser->uid;
392 conn->gid = vuser->gid;
393 string_set(&conn->user,vuser->user.unix_name);
394 fstrcpy(user,vuser->user.unix_name);
395 guest = vuser->guest;
396 } else if (lp_security() == SEC_SHARE) {
397 /* add it as a possible user name if we
398 are in share mode security */
399 add_session_user(lp_servicename(snum));
400 /* shall we let them in? */
401 if (!authorise_login(snum,user,password,&guest)) {
402 DEBUG( 2, ( "Invalid username/password for [%s]\n",
403 lp_servicename(snum)) );
404 conn_free(conn);
405 *status = NT_STATUS_WRONG_PASSWORD;
406 return NULL;
408 pass = Get_Pwnam(user);
409 conn->force_user = True;
410 conn->uid = pass->pw_uid;
411 conn->gid = pass->pw_gid;
412 string_set(&conn->user, pass->pw_name);
413 fstrcpy(user, pass->pw_name);
415 } else {
416 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
417 conn_free(conn);
418 *status = NT_STATUS_ACCESS_DENIED;
419 return NULL;
422 add_session_user(user);
424 safe_strcpy(conn->client_address, client_addr(),
425 sizeof(conn->client_address)-1);
426 conn->num_files_open = 0;
427 conn->lastused = time(NULL);
428 conn->service = snum;
429 conn->used = True;
430 conn->printer = (strncmp(dev,"LPT",3) == 0);
431 conn->ipc = ((strncmp(dev,"IPC",3) == 0) || strequal(dev,"ADMIN$"));
432 conn->dirptr = NULL;
433 conn->veto_list = NULL;
434 conn->hide_list = NULL;
435 conn->veto_oplock_list = NULL;
436 string_set(&conn->dirpath,"");
437 string_set(&conn->user,user);
438 conn->nt_user_token = NULL;
440 set_read_only(conn, vuser ? vuser->groups : NULL, vuser ? vuser->n_groups : 0);
442 set_admin_user(conn, vuser ? vuser->groups : NULL, vuser ? vuser->n_groups : 0);
445 * If force user is true, then store the
446 * given userid and also the groups
447 * of the user we're forcing.
450 if (*lp_force_user(snum)) {
451 struct passwd *pass2;
452 pstring fuser;
453 pstrcpy(fuser,lp_force_user(snum));
455 /* Allow %S to be used by force user. */
456 pstring_sub(fuser,"%S",lp_servicename(snum));
458 pass2 = (struct passwd *)Get_Pwnam(fuser);
459 if (pass2) {
460 conn->uid = pass2->pw_uid;
461 conn->gid = pass2->pw_gid;
462 string_set(&conn->user,pass2->pw_name);
463 fstrcpy(user,pass2->pw_name);
464 conn->force_user = True;
465 DEBUG(3,("Forced user %s\n",user));
466 } else {
467 DEBUG(1,("Couldn't find user %s\n",fuser));
468 conn_free(conn);
469 *status = NT_STATUS_NO_SUCH_USER;
470 return NULL;
474 /* admin users always run as uid=0 */
475 if (conn->admin_user) {
476 conn->uid = 0;
479 #ifdef HAVE_GETGRNAM
481 * If force group is true, then override
482 * any groupid stored for the connecting user.
485 if (*lp_force_group(snum)) {
486 gid_t gid;
487 pstring gname;
488 pstring tmp_gname;
489 BOOL user_must_be_member = False;
491 pstrcpy(tmp_gname,lp_force_group(snum));
493 if (tmp_gname[0] == '+') {
494 user_must_be_member = True;
495 /* even now, tmp_gname is null terminated */
496 pstrcpy(gname,&tmp_gname[1]);
497 } else {
498 pstrcpy(gname,tmp_gname);
500 /* default service may be a group name */
501 pstring_sub(gname,"%S",lp_servicename(snum));
502 gid = nametogid(gname);
504 if (gid != (gid_t)-1) {
507 * If the user has been forced and the forced group starts
508 * with a '+', then we only set the group to be the forced
509 * group if the forced user is a member of that group.
510 * Otherwise, the meaning of the '+' would be ignored.
512 if (conn->force_user && user_must_be_member) {
513 if (user_in_group_list( user, gname, NULL, 0)) {
514 conn->gid = gid;
515 DEBUG(3,("Forced group %s for member %s\n",gname,user));
517 } else {
518 conn->gid = gid;
519 DEBUG(3,("Forced group %s\n",gname));
521 conn->force_group = True;
522 } else {
523 DEBUG(1,("Couldn't find group %s\n",gname));
524 conn_free(conn);
525 *status = NT_STATUS_NO_SUCH_GROUP;
526 return NULL;
529 #endif /* HAVE_GETGRNAM */
532 pstring s;
533 pstrcpy(s,lp_pathname(snum));
534 standard_sub_conn(conn,s,sizeof(s));
535 string_set(&conn->connectpath,s);
536 DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum)));
539 if (conn->force_user || conn->force_group) {
541 /* groups stuff added by ih */
542 conn->ngroups = 0;
543 conn->groups = NULL;
545 /* Find all the groups this uid is in and
546 store them. Used by change_to_user() */
547 initialise_groups(conn->user, conn->uid, conn->gid);
548 get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
550 conn->nt_user_token = create_nt_token(conn->uid, conn->gid,
551 conn->ngroups, conn->groups,
552 guest);
556 * New code to check if there's a share security descripter
557 * added from NT server manager. This is done after the
558 * smb.conf checks are done as we need a uid and token. JRA.
563 BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA);
565 if (!can_write) {
566 if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) {
567 /* No access, read or write. */
568 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
569 lp_servicename(snum)));
570 conn_free(conn);
571 *status = NT_STATUS_ACCESS_DENIED;
572 return NULL;
573 } else {
574 conn->read_only = True;
578 /* Initialise VFS function pointers */
580 if (!smbd_vfs_init(conn)) {
581 DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn))));
582 conn_free(conn);
583 *status = NT_STATUS_BAD_NETWORK_NAME;
584 return NULL;
587 /* ROOT Activities: */
588 /* check number of connections */
589 if (!claim_connection(conn,
590 lp_servicename(SNUM(conn)),
591 lp_max_connections(SNUM(conn)),
592 False,0)) {
593 DEBUG(1,("too many connections - rejected\n"));
594 conn_free(conn);
595 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
596 return NULL;
599 /* Preexecs are done here as they might make the dir we are to ChDir to below */
600 /* execute any "root preexec = " line */
601 if (*lp_rootpreexec(SNUM(conn))) {
602 int ret;
603 pstring cmd;
604 pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
605 standard_sub_conn(conn,cmd,sizeof(cmd));
606 DEBUG(5,("cmd=%s\n",cmd));
607 ret = smbrun(cmd,NULL);
608 if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
609 DEBUG(1,("root preexec gave %d - failing connection\n", ret));
610 yield_connection(conn, lp_servicename(SNUM(conn)));
611 conn_free(conn);
612 *status = NT_STATUS_ACCESS_DENIED;
613 return NULL;
617 /* USER Activites: */
618 if (!change_to_user(conn, conn->vuid)) {
619 /* No point continuing if they fail the basic checks */
620 DEBUG(0,("Can't become connected user!\n"));
621 conn_free(conn);
622 *status = NT_STATUS_LOGON_FAILURE;
623 return NULL;
626 /* Remember that a different vuid can connect later without these checks... */
628 /* Preexecs are done here as they might make the dir we are to ChDir to below */
629 /* execute any "preexec = " line */
630 if (*lp_preexec(SNUM(conn))) {
631 int ret;
632 pstring cmd;
633 pstrcpy(cmd,lp_preexec(SNUM(conn)));
634 standard_sub_conn(conn,cmd,sizeof(cmd));
635 ret = smbrun(cmd,NULL);
636 if (ret != 0 && lp_preexec_close(SNUM(conn))) {
637 DEBUG(1,("preexec gave %d - failing connection\n", ret));
638 change_to_root_user();
639 yield_connection(conn, lp_servicename(SNUM(conn)));
640 conn_free(conn);
641 *status = NT_STATUS_ACCESS_DENIED;
642 return NULL;
646 #ifdef WITH_FAKE_KASERVER
647 if (lp_afs_share(SNUM(conn))) {
648 afs_login(conn);
650 #endif
652 #if CHECK_PATH_ON_TCONX
653 /* win2000 does not check the permissions on the directory
654 during the tree connect, instead relying on permission
655 check during individual operations. To match this behaviour
656 I have disabled this chdir check (tridge) */
657 if (vfs_ChDir(conn,conn->connectpath) != 0) {
658 DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
659 get_remote_machine_name(), conn->client_address,
660 conn->connectpath,strerror(errno)));
661 change_to_root_user();
662 yield_connection(conn, lp_servicename(SNUM(conn)));
663 conn_free(conn);
664 *status = NT_STATUS_BAD_NETWORK_NAME;
665 return NULL;
667 #else
668 /* the alternative is just to check the directory exists */
669 if (stat(conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
670 DEBUG(0,("'%s' does not exist or is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(SNUM(conn))));
671 change_to_root_user();
672 yield_connection(conn, lp_servicename(SNUM(conn)));
673 conn_free(conn);
674 *status = NT_STATUS_BAD_NETWORK_NAME;
675 return NULL;
677 #endif
679 string_set(&conn->origpath,conn->connectpath);
681 #if SOFTLINK_OPTIMISATION
682 /* resolve any soft links early if possible */
683 if (vfs_ChDir(conn,conn->connectpath) == 0) {
684 pstring s;
685 pstrcpy(s,conn->connectpath);
686 vfs_GetWd(conn,s);
687 string_set(&conn->connectpath,s);
688 vfs_ChDir(conn,conn->connectpath);
690 #endif
693 * Print out the 'connected as' stuff here as we need
694 * to know the effective uid and gid we will be using
695 * (at least initially).
698 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
699 dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address );
700 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
701 dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
702 dbgtext( "initially as user %s ", user );
703 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
704 dbgtext( "(pid %d)\n", (int)sys_getpid() );
707 /* Add veto/hide lists */
708 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
709 set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
710 set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
711 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
714 /* Invoke VFS make connection hook */
716 if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
717 DEBUG(0,("make_connection: VFS make connection failed!\n"));
718 change_to_root_user();
719 conn_free(conn);
720 *status = NT_STATUS_UNSUCCESSFUL;
721 return NULL;
724 /* we've finished with the user stuff - go back to root */
725 change_to_root_user();
727 return(conn);
730 /***************************************************************************************
731 Simple wrapper function for make_connection() to include a call to
732 vfs_chdir()
733 **************************************************************************************/
735 connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password,
736 const char *dev, uint16 vuid, NTSTATUS *status)
738 connection_struct *conn = NULL;
740 conn = make_connection(service_in, password, dev, vuid, status);
743 * make_connection() does not change the directory for us any more
744 * so we have to do it as a separate step --jerry
747 if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
748 DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n",
749 conn->connectpath,strerror(errno)));
750 yield_connection(conn, lp_servicename(SNUM(conn)));
751 conn_free(conn);
752 *status = NT_STATUS_UNSUCCESSFUL;
753 return NULL;
756 return conn;
759 /****************************************************************************
760 Make a connection to a service.
762 * @param service
763 ****************************************************************************/
765 connection_struct *make_connection(const char *service_in, DATA_BLOB password,
766 const char *pdev, uint16 vuid, NTSTATUS *status)
768 uid_t euid;
769 user_struct *vuser = NULL;
770 fstring service;
771 fstring dev;
772 int snum = -1;
774 fstrcpy(dev, pdev);
776 /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
777 if (!non_root_mode() && (euid = geteuid()) != 0) {
778 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
779 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
782 if(lp_security() != SEC_SHARE) {
783 vuser = get_valid_user_struct(vuid);
784 if (!vuser) {
785 DEBUG(1,("make_connection: refusing to connect with no session setup\n"));
786 *status = NT_STATUS_ACCESS_DENIED;
787 return NULL;
791 /* Logic to try and connect to the correct [homes] share, preferably without too many
792 getpwnam() lookups. This is particulary nasty for winbind usernames, where the
793 share name isn't the same as unix username.
795 The snum of the homes share is stored on the vuser at session setup time.
798 if (strequal(service_in,HOMES_NAME)) {
799 if(lp_security() != SEC_SHARE) {
800 DATA_BLOB no_pw = data_blob(NULL, 0);
801 if (vuser->homes_snum == -1) {
802 DEBUG(2, ("[homes] share not available for this user because it was not found or created at session setup time\n"));
803 *status = NT_STATUS_BAD_NETWORK_NAME;
804 return NULL;
806 DEBUG(5, ("making a connection to [homes] service created at session setup time\n"));
807 return make_connection_snum(vuser->homes_snum,
808 vuser, no_pw,
809 dev, status);
810 } else {
811 /* Security = share. Try with current_user_info.smb_name
812 * as the username. */
813 if (*current_user_info.smb_name) {
814 fstring unix_username;
815 fstrcpy(unix_username,
816 current_user_info.smb_name);
817 map_username(unix_username);
818 snum = find_service(unix_username);
820 if (snum != -1) {
821 DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in));
822 return make_connection_snum(snum, NULL,
823 password,
824 dev, status);
827 } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
828 && strequal(service_in, lp_servicename(vuser->homes_snum))) {
829 DATA_BLOB no_pw = data_blob(NULL, 0);
830 DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service_in));
831 return make_connection_snum(vuser->homes_snum,
832 vuser, no_pw,
833 dev, status);
836 fstrcpy(service, service_in);
838 strlower_m(service);
840 snum = find_service(service);
842 if (snum < 0) {
843 if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
844 DEBUG(3,("refusing IPC connection to %s\n", service));
845 *status = NT_STATUS_ACCESS_DENIED;
846 return NULL;
849 DEBUG(0,("%s (%s) couldn't find service %s\n",
850 get_remote_machine_name(), client_addr(), service));
851 *status = NT_STATUS_BAD_NETWORK_NAME;
852 return NULL;
855 /* Handle non-Dfs clients attempting connections to msdfs proxy */
856 if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) {
857 DEBUG(3, ("refusing connection to dfs proxy '%s'\n", service));
858 *status = NT_STATUS_BAD_NETWORK_NAME;
859 return NULL;
862 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
864 return make_connection_snum(snum, vuser,
865 password,
866 dev, status);
869 /****************************************************************************
870 close a cnum
871 ****************************************************************************/
872 void close_cnum(connection_struct *conn, uint16 vuid)
874 DirCacheFlush(SNUM(conn));
876 change_to_root_user();
878 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
879 get_remote_machine_name(),conn->client_address,
880 lp_servicename(SNUM(conn))));
882 /* Call VFS disconnect hook */
883 SMB_VFS_DISCONNECT(conn);
885 yield_connection(conn, lp_servicename(SNUM(conn)));
887 file_close_conn(conn);
888 dptr_closecnum(conn);
890 /* execute any "postexec = " line */
891 if (*lp_postexec(SNUM(conn)) &&
892 change_to_user(conn, vuid)) {
893 pstring cmd;
894 pstrcpy(cmd,lp_postexec(SNUM(conn)));
895 standard_sub_conn(conn,cmd,sizeof(cmd));
896 smbrun(cmd,NULL);
897 change_to_root_user();
900 change_to_root_user();
901 /* execute any "root postexec = " line */
902 if (*lp_rootpostexec(SNUM(conn))) {
903 pstring cmd;
904 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
905 standard_sub_conn(conn,cmd,sizeof(cmd));
906 smbrun(cmd,NULL);
909 /* make sure we leave the directory available for unmount */
910 vfs_ChDir(conn, "/");
912 conn_free(conn);