r799: BUG 1259 -- add 'printcap cache time' patch from Lars
[Samba/ekacnet.git] / source / smbd / service.c
blobc74537c299e14c67a78863281095661338afc63a
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,BOOL do_chdir)
33 extern char magic_char;
34 static connection_struct *last_conn;
35 int snum;
37 if (!conn) {
38 last_conn = NULL;
39 return(False);
42 conn->lastused = smb_last_time.tv_sec;
44 snum = SNUM(conn);
46 if (do_chdir &&
47 vfs_ChDir(conn,conn->connectpath) != 0 &&
48 vfs_ChDir(conn,conn->origpath) != 0) {
49 DEBUG(0,("chdir (%s) failed\n",
50 conn->connectpath));
51 return(False);
54 if (conn == last_conn)
55 return(True);
57 last_conn = conn;
59 magic_char = lp_magicchar(snum);
60 return(True);
63 /****************************************************************************
64 Add a home service. Returns the new service number or -1 if fail.
65 ****************************************************************************/
67 int add_home_service(const char *service, const char *username, const char *homedir)
69 int iHomeService;
71 if (!service || !homedir)
72 return -1;
74 if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
75 return -1;
78 * If this is a winbindd provided username, remove
79 * the domain component before adding the service.
80 * Log a warning if the "path=" parameter does not
81 * include any macros.
85 const char *p = strchr(service,*lp_winbind_separator());
87 /* We only want the 'user' part of the string */
88 if (p) {
89 service = p + 1;
93 if (!lp_add_home(service, iHomeService, username, homedir)) {
94 return -1;
97 return lp_servicenumber(service);
103 * Find a service entry.
105 * @param service is modified (to canonical form??)
108 int find_service(fstring service)
110 int iService;
112 all_string_sub(service,"\\","/",0);
114 iService = lp_servicenumber(service);
116 /* now handle the special case of a home directory */
117 if (iService < 0) {
118 char *phome_dir = get_user_home_dir(service);
120 if(!phome_dir) {
122 * Try mapping the servicename, it may
123 * be a Windows to unix mapped user name.
125 if(map_username(service))
126 phome_dir = get_user_home_dir(service);
129 DEBUG(3,("checking for home directory %s gave %s\n",service,
130 phome_dir?phome_dir:"(NULL)"));
132 iService = add_home_service(service,service /* 'username' */, phome_dir);
135 /* If we still don't have a service, attempt to add it as a printer. */
136 if (iService < 0) {
137 int iPrinterService;
139 if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0) {
140 char *pszTemp;
142 DEBUG(3,("checking whether %s is a valid printer name...\n", service));
143 pszTemp = lp_printcapname();
144 if ((pszTemp != NULL) && pcap_printername_ok(service, pszTemp)) {
145 DEBUG(3,("%s is a valid printer name\n", service));
146 DEBUG(3,("adding %s as a printer service\n", service));
147 lp_add_printer(service, iPrinterService);
148 iService = lp_servicenumber(service);
149 if (iService < 0) {
150 DEBUG(0,("failed to add %s as a printer service!\n", service));
152 } else {
153 DEBUG(3,("%s is not a valid printer name\n", service));
158 /* Check for default vfs service? Unsure whether to implement this */
159 if (iService < 0) {
162 /* just possibly it's a default service? */
163 if (iService < 0) {
164 char *pdefservice = lp_defaultservice();
165 if (pdefservice && *pdefservice && !strequal(pdefservice,service) && !strstr_m(service,"..")) {
167 * We need to do a local copy here as lp_defaultservice()
168 * returns one of the rotating lp_string buffers that
169 * could get overwritten by the recursive find_service() call
170 * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
172 pstring defservice;
173 pstrcpy(defservice, pdefservice);
174 iService = find_service(defservice);
175 if (iService >= 0) {
176 all_string_sub(service, "_","/",0);
177 iService = lp_add_service(service, iService);
182 if (iService >= 0) {
183 if (!VALID_SNUM(iService)) {
184 DEBUG(0,("Invalid snum %d for %s\n",iService, service));
185 iService = -1;
189 if (iService < 0)
190 DEBUG(3,("find_service() failed to find service %s\n", service));
192 return (iService);
196 /****************************************************************************
197 do some basic sainity checks on the share.
198 This function modifies dev, ecode.
199 ****************************************************************************/
201 static NTSTATUS share_sanity_checks(int snum, fstring dev)
204 if (!lp_snum_ok(snum) ||
205 !check_access(smbd_server_fd(),
206 lp_hostsallow(snum), lp_hostsdeny(snum))) {
207 return NT_STATUS_ACCESS_DENIED;
210 if (dev[0] == '?' || !dev[0]) {
211 if (lp_print_ok(snum)) {
212 fstrcpy(dev,"LPT1:");
213 } else if (strequal(lp_fstype(snum), "IPC")) {
214 fstrcpy(dev, "IPC");
215 } else {
216 fstrcpy(dev,"A:");
220 strupper_m(dev);
222 if (lp_print_ok(snum)) {
223 if (!strequal(dev, "LPT1:")) {
224 return NT_STATUS_BAD_DEVICE_TYPE;
226 } else if (strequal(lp_fstype(snum), "IPC")) {
227 if (!strequal(dev, "IPC")) {
228 return NT_STATUS_BAD_DEVICE_TYPE;
230 } else if (!strequal(dev, "A:")) {
231 return NT_STATUS_BAD_DEVICE_TYPE;
234 /* Behave as a printer if we are supposed to */
235 if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
236 fstrcpy(dev, "LPT1:");
239 return NT_STATUS_OK;
242 /****************************************************************************
243 Make a connection, given the snum to connect to, and the vuser of the
244 connecting user if appropriate.
245 ****************************************************************************/
247 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
248 DATA_BLOB password,
249 const char *pdev, NTSTATUS *status)
251 struct passwd *pass = NULL;
252 BOOL guest = False;
253 connection_struct *conn;
254 struct stat st;
255 fstring user;
256 fstring dev;
258 *user = 0;
259 fstrcpy(dev, pdev);
261 if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
262 return NULL;
265 conn = conn_new();
266 if (!conn) {
267 DEBUG(0,("Couldn't find free connection.\n"));
268 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
269 return NULL;
272 if (lp_guest_only(snum)) {
273 const char *guestname = lp_guestaccount();
274 guest = True;
275 pass = getpwnam_alloc(guestname);
276 if (!pass) {
277 DEBUG(0,("make_connection_snum: Invalid guest account %s??\n",guestname));
278 conn_free(conn);
279 *status = NT_STATUS_NO_SUCH_USER;
280 return NULL;
282 fstrcpy(user,pass->pw_name);
283 conn->force_user = True;
284 conn->uid = pass->pw_uid;
285 conn->gid = pass->pw_gid;
286 string_set(&conn->user,pass->pw_name);
287 passwd_free(&pass);
288 DEBUG(3,("Guest only user %s\n",user));
289 } else if (vuser) {
290 if (vuser->guest) {
291 if (!lp_guest_ok(snum)) {
292 DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)\n", lp_servicename(snum)));
293 conn_free(conn);
294 *status = NT_STATUS_ACCESS_DENIED;
295 return NULL;
297 } else {
298 if (!user_ok(vuser->user.unix_name, snum, vuser->groups, vuser->n_groups)) {
299 DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)\n", vuser->user.unix_name, lp_servicename(snum)));
300 conn_free(conn);
301 *status = NT_STATUS_ACCESS_DENIED;
302 return NULL;
305 conn->vuid = vuser->vuid;
306 conn->uid = vuser->uid;
307 conn->gid = vuser->gid;
308 string_set(&conn->user,vuser->user.unix_name);
309 fstrcpy(user,vuser->user.unix_name);
310 guest = vuser->guest;
311 } else if (lp_security() == SEC_SHARE) {
312 /* add it as a possible user name if we
313 are in share mode security */
314 add_session_user(lp_servicename(snum));
315 /* shall we let them in? */
316 if (!authorise_login(snum,user,password,&guest)) {
317 DEBUG( 2, ( "Invalid username/password for [%s]\n",
318 lp_servicename(snum)) );
319 conn_free(conn);
320 *status = NT_STATUS_WRONG_PASSWORD;
321 return NULL;
323 pass = Get_Pwnam(user);
324 conn->force_user = True;
325 conn->uid = pass->pw_uid;
326 conn->gid = pass->pw_gid;
327 string_set(&conn->user, pass->pw_name);
328 fstrcpy(user, pass->pw_name);
330 } else {
331 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
332 conn_free(conn);
333 *status = NT_STATUS_ACCESS_DENIED;
334 return NULL;
337 add_session_user(user);
339 safe_strcpy(conn->client_address, client_addr(),
340 sizeof(conn->client_address)-1);
341 conn->num_files_open = 0;
342 conn->lastused = time(NULL);
343 conn->service = snum;
344 conn->used = True;
345 conn->printer = (strncmp(dev,"LPT",3) == 0);
346 conn->ipc = ((strncmp(dev,"IPC",3) == 0) || strequal(dev,"ADMIN$"));
347 conn->dirptr = NULL;
349 /* Case options for the share. */
350 conn->case_sensitive = lp_casesensitive(snum);
351 conn->case_preserve = lp_preservecase(snum);
352 conn->short_case_preserve = lp_shortpreservecase(snum);
354 conn->veto_list = NULL;
355 conn->hide_list = NULL;
356 conn->veto_oplock_list = NULL;
357 string_set(&conn->dirpath,"");
358 string_set(&conn->user,user);
359 conn->nt_user_token = NULL;
361 conn->read_only = lp_readonly(conn->service);
362 conn->admin_user = False;
365 * If force user is true, then store the
366 * given userid and also the groups
367 * of the user we're forcing.
370 if (*lp_force_user(snum)) {
371 struct passwd *pass2;
372 pstring fuser;
373 pstrcpy(fuser,lp_force_user(snum));
375 /* Allow %S to be used by force user. */
376 pstring_sub(fuser,"%S",lp_servicename(snum));
378 pass2 = (struct passwd *)Get_Pwnam(fuser);
379 if (pass2) {
380 conn->uid = pass2->pw_uid;
381 conn->gid = pass2->pw_gid;
382 string_set(&conn->user,pass2->pw_name);
383 fstrcpy(user,pass2->pw_name);
384 conn->force_user = True;
385 DEBUG(3,("Forced user %s\n",user));
386 } else {
387 DEBUG(1,("Couldn't find user %s\n",fuser));
388 conn_free(conn);
389 *status = NT_STATUS_NO_SUCH_USER;
390 return NULL;
394 #ifdef HAVE_GETGRNAM
396 * If force group is true, then override
397 * any groupid stored for the connecting user.
400 if (*lp_force_group(snum)) {
401 gid_t gid;
402 pstring gname;
403 pstring tmp_gname;
404 BOOL user_must_be_member = False;
406 pstrcpy(tmp_gname,lp_force_group(snum));
408 if (tmp_gname[0] == '+') {
409 user_must_be_member = True;
410 /* even now, tmp_gname is null terminated */
411 pstrcpy(gname,&tmp_gname[1]);
412 } else {
413 pstrcpy(gname,tmp_gname);
415 /* default service may be a group name */
416 pstring_sub(gname,"%S",lp_servicename(snum));
417 gid = nametogid(gname);
419 if (gid != (gid_t)-1) {
422 * If the user has been forced and the forced group starts
423 * with a '+', then we only set the group to be the forced
424 * group if the forced user is a member of that group.
425 * Otherwise, the meaning of the '+' would be ignored.
427 if (conn->force_user && user_must_be_member) {
428 if (user_in_group_list( user, gname, NULL, 0)) {
429 conn->gid = gid;
430 DEBUG(3,("Forced group %s for member %s\n",gname,user));
432 } else {
433 conn->gid = gid;
434 DEBUG(3,("Forced group %s\n",gname));
436 conn->force_group = True;
437 } else {
438 DEBUG(1,("Couldn't find group %s\n",gname));
439 conn_free(conn);
440 *status = NT_STATUS_NO_SUCH_GROUP;
441 return NULL;
444 #endif /* HAVE_GETGRNAM */
447 pstring s;
448 pstrcpy(s,lp_pathname(snum));
449 standard_sub_conn(conn,s,sizeof(s));
450 string_set(&conn->connectpath,s);
451 DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum)));
454 if (conn->force_user || conn->force_group) {
456 /* groups stuff added by ih */
457 conn->ngroups = 0;
458 conn->groups = NULL;
460 /* Find all the groups this uid is in and
461 store them. Used by change_to_user() */
462 initialise_groups(conn->user, conn->uid, conn->gid);
463 get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
465 conn->nt_user_token = create_nt_token(conn->uid, conn->gid,
466 conn->ngroups, conn->groups,
467 guest);
471 * New code to check if there's a share security descripter
472 * added from NT server manager. This is done after the
473 * smb.conf checks are done as we need a uid and token. JRA.
478 BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA);
480 if (!can_write) {
481 if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) {
482 /* No access, read or write. */
483 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
484 lp_servicename(snum)));
485 conn_free(conn);
486 *status = NT_STATUS_ACCESS_DENIED;
487 return NULL;
488 } else {
489 conn->read_only = True;
493 /* Initialise VFS function pointers */
495 if (!smbd_vfs_init(conn)) {
496 DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn))));
497 conn_free(conn);
498 *status = NT_STATUS_BAD_NETWORK_NAME;
499 return NULL;
502 /* ROOT Activities: */
503 /* check number of connections */
504 if (!claim_connection(conn,
505 lp_servicename(SNUM(conn)),
506 lp_max_connections(SNUM(conn)),
507 False,0)) {
508 DEBUG(1,("too many connections - rejected\n"));
509 conn_free(conn);
510 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
511 return NULL;
514 /* Preexecs are done here as they might make the dir we are to ChDir to below */
515 /* execute any "root preexec = " line */
516 if (*lp_rootpreexec(SNUM(conn))) {
517 int ret;
518 pstring cmd;
519 pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
520 standard_sub_conn(conn,cmd,sizeof(cmd));
521 DEBUG(5,("cmd=%s\n",cmd));
522 ret = smbrun(cmd,NULL);
523 if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
524 DEBUG(1,("root preexec gave %d - failing connection\n", ret));
525 yield_connection(conn, lp_servicename(SNUM(conn)));
526 conn_free(conn);
527 *status = NT_STATUS_ACCESS_DENIED;
528 return NULL;
532 /* USER Activites: */
533 if (!change_to_user(conn, conn->vuid)) {
534 /* No point continuing if they fail the basic checks */
535 DEBUG(0,("Can't become connected user!\n"));
536 conn_free(conn);
537 *status = NT_STATUS_LOGON_FAILURE;
538 return NULL;
541 /* Remember that a different vuid can connect later without these checks... */
543 /* Preexecs are done here as they might make the dir we are to ChDir to below */
544 /* execute any "preexec = " line */
545 if (*lp_preexec(SNUM(conn))) {
546 int ret;
547 pstring cmd;
548 pstrcpy(cmd,lp_preexec(SNUM(conn)));
549 standard_sub_conn(conn,cmd,sizeof(cmd));
550 ret = smbrun(cmd,NULL);
551 if (ret != 0 && lp_preexec_close(SNUM(conn))) {
552 DEBUG(1,("preexec gave %d - failing connection\n", ret));
553 change_to_root_user();
554 yield_connection(conn, lp_servicename(SNUM(conn)));
555 conn_free(conn);
556 *status = NT_STATUS_ACCESS_DENIED;
557 return NULL;
561 #ifdef WITH_FAKE_KASERVER
562 if (lp_afs_share(SNUM(conn))) {
563 afs_login(conn);
565 #endif
567 #if CHECK_PATH_ON_TCONX
568 /* win2000 does not check the permissions on the directory
569 during the tree connect, instead relying on permission
570 check during individual operations. To match this behaviour
571 I have disabled this chdir check (tridge) */
572 if (vfs_ChDir(conn,conn->connectpath) != 0) {
573 DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
574 get_remote_machine_name(), conn->client_address,
575 conn->connectpath,strerror(errno)));
576 change_to_root_user();
577 yield_connection(conn, lp_servicename(SNUM(conn)));
578 conn_free(conn);
579 *status = NT_STATUS_BAD_NETWORK_NAME;
580 return NULL;
582 #else
583 /* the alternative is just to check the directory exists */
584 if (stat(conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
585 DEBUG(0,("'%s' does not exist or is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(SNUM(conn))));
586 change_to_root_user();
587 yield_connection(conn, lp_servicename(SNUM(conn)));
588 conn_free(conn);
589 *status = NT_STATUS_BAD_NETWORK_NAME;
590 return NULL;
592 #endif
594 string_set(&conn->origpath,conn->connectpath);
596 #if SOFTLINK_OPTIMISATION
597 /* resolve any soft links early if possible */
598 if (vfs_ChDir(conn,conn->connectpath) == 0) {
599 pstring s;
600 pstrcpy(s,conn->connectpath);
601 vfs_GetWd(conn,s);
602 string_set(&conn->connectpath,s);
603 vfs_ChDir(conn,conn->connectpath);
605 #endif
608 * Print out the 'connected as' stuff here as we need
609 * to know the effective uid and gid we will be using
610 * (at least initially).
613 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
614 dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address );
615 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
616 dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
617 dbgtext( "initially as user %s ", user );
618 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
619 dbgtext( "(pid %d)\n", (int)sys_getpid() );
622 /* Add veto/hide lists */
623 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
624 set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
625 set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
626 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
629 /* Invoke VFS make connection hook */
631 if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
632 DEBUG(0,("make_connection: VFS make connection failed!\n"));
633 change_to_root_user();
634 conn_free(conn);
635 *status = NT_STATUS_UNSUCCESSFUL;
636 return NULL;
639 /* we've finished with the user stuff - go back to root */
640 change_to_root_user();
642 return(conn);
645 /***************************************************************************************
646 Simple wrapper function for make_connection() to include a call to
647 vfs_chdir()
648 **************************************************************************************/
650 connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password,
651 const char *dev, uint16 vuid, NTSTATUS *status)
653 connection_struct *conn = NULL;
655 conn = make_connection(service_in, password, dev, vuid, status);
658 * make_connection() does not change the directory for us any more
659 * so we have to do it as a separate step --jerry
662 if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
663 DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n",
664 conn->connectpath,strerror(errno)));
665 yield_connection(conn, lp_servicename(SNUM(conn)));
666 conn_free(conn);
667 *status = NT_STATUS_UNSUCCESSFUL;
668 return NULL;
671 return conn;
674 /****************************************************************************
675 Make a connection to a service.
677 * @param service
678 ****************************************************************************/
680 connection_struct *make_connection(const char *service_in, DATA_BLOB password,
681 const char *pdev, uint16 vuid, NTSTATUS *status)
683 uid_t euid;
684 user_struct *vuser = NULL;
685 fstring service;
686 fstring dev;
687 int snum = -1;
689 fstrcpy(dev, pdev);
691 /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
692 if (!non_root_mode() && (euid = geteuid()) != 0) {
693 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
694 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
697 if(lp_security() != SEC_SHARE) {
698 vuser = get_valid_user_struct(vuid);
699 if (!vuser) {
700 DEBUG(1,("make_connection: refusing to connect with no session setup\n"));
701 *status = NT_STATUS_ACCESS_DENIED;
702 return NULL;
706 /* Logic to try and connect to the correct [homes] share, preferably without too many
707 getpwnam() lookups. This is particulary nasty for winbind usernames, where the
708 share name isn't the same as unix username.
710 The snum of the homes share is stored on the vuser at session setup time.
713 if (strequal(service_in,HOMES_NAME)) {
714 if(lp_security() != SEC_SHARE) {
715 DATA_BLOB no_pw = data_blob(NULL, 0);
716 if (vuser->homes_snum == -1) {
717 DEBUG(2, ("[homes] share not available for this user because it was not found or created at session setup time\n"));
718 *status = NT_STATUS_BAD_NETWORK_NAME;
719 return NULL;
721 DEBUG(5, ("making a connection to [homes] service created at session setup time\n"));
722 return make_connection_snum(vuser->homes_snum,
723 vuser, no_pw,
724 dev, status);
725 } else {
726 /* Security = share. Try with current_user_info.smb_name
727 * as the username. */
728 if (*current_user_info.smb_name) {
729 fstring unix_username;
730 fstrcpy(unix_username,
731 current_user_info.smb_name);
732 map_username(unix_username);
733 snum = find_service(unix_username);
735 if (snum != -1) {
736 DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in));
737 return make_connection_snum(snum, NULL,
738 password,
739 dev, status);
742 } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
743 && strequal(service_in, lp_servicename(vuser->homes_snum))) {
744 DATA_BLOB no_pw = data_blob(NULL, 0);
745 DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service_in));
746 return make_connection_snum(vuser->homes_snum,
747 vuser, no_pw,
748 dev, status);
751 fstrcpy(service, service_in);
753 strlower_m(service);
755 snum = find_service(service);
757 if (snum < 0) {
758 if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
759 DEBUG(3,("refusing IPC connection to %s\n", service));
760 *status = NT_STATUS_ACCESS_DENIED;
761 return NULL;
764 DEBUG(0,("%s (%s) couldn't find service %s\n",
765 get_remote_machine_name(), client_addr(), service));
766 *status = NT_STATUS_BAD_NETWORK_NAME;
767 return NULL;
770 /* Handle non-Dfs clients attempting connections to msdfs proxy */
771 if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) {
772 DEBUG(3, ("refusing connection to dfs proxy '%s'\n", service));
773 *status = NT_STATUS_BAD_NETWORK_NAME;
774 return NULL;
777 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
779 return make_connection_snum(snum, vuser,
780 password,
781 dev, status);
784 /****************************************************************************
785 close a cnum
786 ****************************************************************************/
787 void close_cnum(connection_struct *conn, uint16 vuid)
789 DirCacheFlush(SNUM(conn));
791 file_close_conn(conn);
792 dptr_closecnum(conn);
794 change_to_root_user();
796 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
797 get_remote_machine_name(),conn->client_address,
798 lp_servicename(SNUM(conn))));
800 /* Call VFS disconnect hook */
801 SMB_VFS_DISCONNECT(conn);
803 yield_connection(conn, lp_servicename(SNUM(conn)));
805 /* make sure we leave the directory available for unmount */
806 vfs_ChDir(conn, "/");
808 /* execute any "postexec = " line */
809 if (*lp_postexec(SNUM(conn)) &&
810 change_to_user(conn, vuid)) {
811 pstring cmd;
812 pstrcpy(cmd,lp_postexec(SNUM(conn)));
813 standard_sub_conn(conn,cmd,sizeof(cmd));
814 smbrun(cmd,NULL);
815 change_to_root_user();
818 change_to_root_user();
819 /* execute any "root postexec = " line */
820 if (*lp_rootpostexec(SNUM(conn))) {
821 pstring cmd;
822 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
823 standard_sub_conn(conn,cmd,sizeof(cmd));
824 smbrun(cmd,NULL);
827 conn_free(conn);
830 /****************************************************************************
831 Remove stale printers
832 ****************************************************************************/
834 void remove_stale_printers( void )
836 int snum, iNumServices, printersServiceNum;
837 const char *pname;
839 iNumServices = lp_numservices();
840 printersServiceNum = lp_servicenumber( PRINTERS_NAME);
841 for( snum = 0; snum < iNumServices; snum++) {
842 /* Never remove PRINTERS_NAME */
843 if ( snum == printersServiceNum)
844 continue;
845 pname = lp_printername( snum);
846 /* Is snum a print service and still in the printing subsystem? */
847 if ( lp_print_ok( snum) && !pcap_printername_ok( pname, NULL)) {
848 DEBUG( 3, ( "Removing printer: %s\n", pname));
849 lp_killservice( snum);