4 Unix SMB/Netbios implementation.
6 service (connection) opening and closing
7 Copyright (C) Andrew Tridgell 1992-1998
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 extern int DEBUGLEVEL;
28 extern struct timeval smb_last_time;
29 extern int case_default;
30 extern BOOL case_preserve;
31 extern BOOL short_case_preserve;
32 extern BOOL case_mangle;
33 extern BOOL case_sensitive;
34 extern BOOL use_mangled_map;
35 extern fstring remote_machine;
36 extern pstring sesssetup_user;
37 extern fstring remote_machine;
40 /****************************************************************************
41 load parameters specific to a connection/service
42 ****************************************************************************/
43 BOOL become_service(connection_struct *conn,BOOL do_chdir)
45 extern char magic_char;
46 static connection_struct *last_conn;
54 conn->lastused = smb_last_time.tv_sec;
59 vfs_ChDir(conn,conn->connectpath) != 0 &&
60 vfs_ChDir(conn,conn->origpath) != 0) {
61 DEBUG(0,("chdir (%s) failed\n",
66 if (conn == last_conn)
71 case_default = lp_defaultcase(snum);
72 case_preserve = lp_preservecase(snum);
73 short_case_preserve = lp_shortpreservecase(snum);
74 case_mangle = lp_casemangle(snum);
75 case_sensitive = lp_casesensitive(snum);
76 magic_char = lp_magicchar(snum);
77 use_mangled_map = (*lp_mangled_map(snum) ? True:False);
82 /****************************************************************************
84 ****************************************************************************/
85 int find_service(char *service)
89 all_string_sub(service,"\\","/",0);
91 iService = lp_servicenumber(service);
93 /* now handle the special case of a home directory */
96 char *phome_dir = get_user_home_dir(service);
101 * Try mapping the servicename, it may
102 * be a Windows to unix mapped user name.
104 if(map_username(service))
105 phome_dir = get_user_home_dir(service);
108 DEBUG(3,("checking for home directory %s gave %s\n",service,
109 phome_dir?phome_dir:"(NULL)"));
114 if ((iHomeService = lp_servicenumber(HOMES_NAME)) >= 0)
116 lp_add_home(service,iHomeService,phome_dir);
117 iService = lp_servicenumber(service);
122 /* If we still don't have a service, attempt to add it as a printer. */
127 if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0)
131 DEBUG(3,("checking whether %s is a valid printer name...\n", service));
133 if ((pszTemp != NULL) && pcap_printername_ok(service, pszTemp))
135 DEBUG(3,("%s is a valid printer name\n", service));
136 DEBUG(3,("adding %s as a printer service\n", service));
137 lp_add_printer(service,iPrinterService);
138 iService = lp_servicenumber(service);
140 DEBUG(0,("failed to add %s as a printer service!\n", service));
143 DEBUG(3,("%s is not a valid printer name\n", service));
147 /* Check for default vfs service? Unsure whether to implement this */
152 /* just possibly it's a default service? */
155 char *pdefservice = lp_defaultservice();
156 if (pdefservice && *pdefservice &&
157 !strequal(pdefservice,service) &&
158 !strstr(service,".."))
161 * We need to do a local copy here as lp_defaultservice()
162 * returns one of the rotating lp_string buffers that
163 * could get overwritten by the recursive find_service() call
164 * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
167 pstrcpy(defservice, pdefservice);
168 iService = find_service(defservice);
171 all_string_sub(service,"_","/",0);
172 iService = lp_add_service(service,iService);
178 if (!VALID_SNUM(iService))
180 DEBUG(0,("Invalid snum %d for %s\n",iService,service));
185 DEBUG(3,("find_service() failed to find service %s\n", service));
191 /****************************************************************************
192 make a connection to a service
193 ****************************************************************************/
194 connection_struct *make_connection(char *service,char *user,char *password, int pwlen, char *dev,uint16 vuid, int *ecode)
197 struct passwd *pass = NULL;
200 connection_struct *conn;
205 snum = find_service(service);
207 if (strequal(service,"IPC$")) {
208 DEBUG(3,("refusing IPC connection\n"));
213 DEBUG(0,("%s (%s) couldn't find service %s\n",
214 remote_machine, client_addr(), service));
215 *ecode = ERRnosuchshare;
219 if (strequal(service,HOMES_NAME)) {
220 if (*user && Get_Pwnam(user,True)) {
221 fstring dos_username;
222 fstrcpy(dos_username, user);
223 unix_to_dos(dos_username, True);
224 return(make_connection(dos_username,user,password,
225 pwlen,dev,vuid,ecode));
228 if(lp_security() != SEC_SHARE) {
229 if (validated_username(vuid)) {
230 fstring dos_username;
231 fstrcpy(user,validated_username(vuid));
232 fstrcpy(dos_username, user);
233 unix_to_dos(dos_username, True);
234 return(make_connection(dos_username,user,password,pwlen,dev,vuid,ecode));
237 /* Security = share. Try with sesssetup_user
238 * as the username. */
239 if(*sesssetup_user) {
240 fstring dos_username;
241 fstrcpy(user,sesssetup_user);
242 fstrcpy(dos_username, user);
243 unix_to_dos(dos_username, True);
244 return(make_connection(dos_username,user,password,pwlen,dev,vuid,ecode));
249 if (!lp_snum_ok(snum) ||
250 !check_access(smbd_server_fd(),
251 lp_hostsallow(snum), lp_hostsdeny(snum))) {
256 /* you can only connect to the IPC$ service as an ipc device */
257 if (strequal(service,"IPC$"))
260 if (*dev == '?' || !*dev) {
261 if (lp_print_ok(snum)) {
262 pstrcpy(dev,"LPT1:");
268 /* if the request is as a printer and you can't print then refuse */
270 if (!lp_print_ok(snum) && (strncmp(dev,"LPT",3) == 0)) {
271 DEBUG(1,("Attempt to connect to non-printer as a printer\n"));
272 *ecode = ERRinvdevice;
276 /* Behave as a printer if we are supposed to */
277 if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
278 pstrcpy(dev, "LPT1:");
281 /* lowercase the user name */
284 /* add it as a possible user name */
285 add_session_user(service);
287 /* shall we let them in? */
288 if (!authorise_login(snum,user,password,pwlen,&guest,&force,vuid)) {
289 DEBUG( 2, ( "Invalid username/password for %s [%s]\n", service, user ) );
296 DEBUG(0,("Couldn't find free connection.\n"));
297 *ecode = ERRnoresource;
302 /* find out some info about the user */
303 pass = smb_getpwnam(user,True);
306 DEBUG(0,( "Couldn't find account %s\n",user));
312 conn->read_only = lp_readonly(snum);
316 StrnCpy(list,lp_readlist(snum),sizeof(pstring)-1);
317 pstring_sub(list,"%S",service);
319 if (user_in_list(user,list))
320 conn->read_only = True;
322 StrnCpy(list,lp_writelist(snum),sizeof(pstring)-1);
323 pstring_sub(list,"%S",service);
325 if (user_in_list(user,list))
326 conn->read_only = False;
329 /* admin user check */
331 /* JRA - original code denied admin user if the share was
332 marked read_only. Changed as I don't think this is needed,
333 but old code left in case there is a problem here.
335 if (user_in_list(user,lp_admin_users(snum))
340 conn->admin_user = True;
341 DEBUG(0,("%s logged in as admin user (root privileges)\n",user));
343 conn->admin_user = False;
346 conn->force_user = force;
348 conn->uid = pass->pw_uid;
349 conn->gid = pass->pw_gid;
350 safe_strcpy(conn->client_address, client_addr(), sizeof(conn->client_address)-1);
351 conn->num_files_open = 0;
352 conn->lastused = time(NULL);
353 conn->service = snum;
355 conn->printer = (strncmp(dev,"LPT",3) == 0);
356 conn->ipc = (strncmp(dev,"IPC",3) == 0);
358 conn->veto_list = NULL;
359 conn->hide_list = NULL;
360 conn->veto_oplock_list = NULL;
361 string_set(&conn->dirpath,"");
362 string_set(&conn->user,user);
363 conn->nt_user_token = NULL;
366 * If force user is true, then store the
367 * given userid and also the primary groupid
368 * of the user we're forcing.
371 if (*lp_force_user(snum)) {
372 struct passwd *pass2;
374 pstrcpy(fuser,lp_force_user(snum));
376 /* Allow %S to be used by force user. */
377 pstring_sub(fuser,"%S",service);
379 pass2 = (struct passwd *)Get_Pwnam(fuser,True);
381 conn->uid = pass2->pw_uid;
382 conn->gid = pass2->pw_gid;
383 string_set(&conn->user,fuser);
385 conn->force_user = True;
386 DEBUG(3,("Forced user %s\n",fuser));
388 DEBUG(1,("Couldn't find user %s\n",fuser));
392 /* admin users always run as uid=0 */
393 if (conn->admin_user) {
399 * If force group is true, then override
400 * any groupid stored for the connecting user.
403 if (*lp_force_group(snum)) {
407 BOOL user_must_be_member = False;
409 StrnCpy(tmp_gname,lp_force_group(snum),sizeof(pstring)-1);
411 if (tmp_gname[0] == '+') {
412 user_must_be_member = True;
413 StrnCpy(gname,&tmp_gname[1],sizeof(pstring)-2);
415 StrnCpy(gname,tmp_gname,sizeof(pstring)-1);
417 /* default service may be a group name */
418 pstring_sub(gname,"%S",service);
419 gptr = (struct group *)getgrnam(gname);
423 * If the user has been forced and the forced group starts
424 * with a '+', then we only set the group to be the forced
425 * group if the forced user is a member of that group.
426 * Otherwise, the meaning of the '+' would be ignored.
428 if (conn->force_user && user_must_be_member) {
430 for (i = 0; gptr->gr_mem[i] != NULL; i++) {
431 if (strcmp(user,gptr->gr_mem[i]) == 0) {
432 conn->gid = gptr->gr_gid;
433 DEBUG(3,("Forced group %s for member %s\n",gname,user));
438 conn->gid = gptr->gr_gid;
439 DEBUG(3,("Forced group %s\n",gname));
442 DEBUG(1,("Couldn't find group %s\n",gname));
445 #endif /* HAVE_GETGRNAM */
449 pstrcpy(s,lp_pathname(snum));
450 standard_sub_conn(conn,s);
451 string_set(&conn->connectpath,s);
452 DEBUG(3,("Connect path is %s\n",s));
455 /* groups stuff added by ih */
460 /* Find all the groups this uid is in and
461 store them. Used by become_user() */
462 initialise_groups(conn->user, conn->uid, conn->gid);
463 initialize_groups(conn->user, conn->uid, conn->gid);
464 get_current_groups(&conn->ngroups,&conn->groups);
466 /* check number of connections */
467 if (!claim_connection(conn,
468 lp_servicename(SNUM(conn)),
469 lp_max_connections(SNUM(conn)),
471 DEBUG(1,("too many connections - rejected\n"));
472 *ecode = ERRnoresource;
477 if (lp_status(SNUM(conn)))
478 claim_connection(conn,"",
482 conn->nt_user_token = create_nt_token(conn->uid, conn->gid, conn->ngroups, conn->groups);
485 * Now initialize the vfs layer.
488 conn->vfs_conn = (struct vfs_connection_struct *)
489 malloc(sizeof(struct vfs_connection_struct));
491 if (conn->vfs_conn == NULL) {
492 DEBUG(0, ("No memory to create vfs_connection_struct"));
496 ZERO_STRUCTP(conn->vfs_conn);
498 /* Copy across relevant data from connection struct */
500 conn->vfs_conn->printer = conn->printer;
501 conn->vfs_conn->ipc = conn->ipc;
502 conn->vfs_conn->read_only = conn->read_only;
503 conn->vfs_conn->admin_user = conn->admin_user;
505 pstrcpy(conn->vfs_conn->dirpath, conn->dirpath);
506 pstrcpy(conn->vfs_conn->connectpath, conn->connectpath);
507 pstrcpy(conn->vfs_conn->origpath, conn->origpath);
509 pstrcpy(conn->vfs_conn->service, service);
510 pstrcpy(conn->vfs_conn->user, conn->user);
512 conn->vfs_conn->uid = conn->uid;
513 conn->vfs_conn->gid = conn->gid;
514 conn->vfs_conn->ngroups = conn->ngroups;
515 if (conn->vfs_conn->ngroups != 0) {
516 conn->vfs_conn->groups = (gid_t *)memdup(conn->groups,
517 conn->ngroups * sizeof(gid_t));
519 conn->vfs_conn->groups = NULL;
522 conn->vfs_conn->nt_user_token = dup_nt_token(conn->nt_user_token);
524 /* Initialise VFS function pointers */
526 if (*lp_vfsobj(SNUM(conn))) {
530 /* Loadable object file */
532 if (!vfs_init_custom(conn)) {
536 DEBUG(0, ("No libdl present - cannot use VFS objects\n"));
543 /* Normal share - initialise with disk access functions */
545 vfs_init_default(conn);
548 /* execute any "root preexec = " line */
549 if (*lp_rootpreexec(SNUM(conn))) {
551 pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
552 standard_sub_conn(conn,cmd);
553 DEBUG(5,("cmd=%s\n",cmd));
554 ret = smbrun(cmd,NULL,False);
555 if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
556 DEBUG(1,("preexec gave %d - failing connection\n", ret));
558 *ecode = ERRsrverror;
563 if (!become_user(conn, conn->vuid)) {
564 DEBUG(0,("Can't become connected user!\n"));
566 yield_connection(conn,
567 lp_servicename(SNUM(conn)),
568 lp_max_connections(SNUM(conn)));
569 if (lp_status(SNUM(conn))) {
570 yield_connection(conn,"",MAXSTATUS);
578 if (vfs_ChDir(conn,conn->connectpath) != 0) {
579 DEBUG(0,("Can't change directory to %s (%s)\n",
580 conn->connectpath,strerror(errno)));
583 yield_connection(conn,
584 lp_servicename(SNUM(conn)),
585 lp_max_connections(SNUM(conn)));
586 if (lp_status(SNUM(conn)))
587 yield_connection(conn,"",MAXSTATUS);
590 *ecode = ERRnosuchshare;
594 string_set(&conn->origpath,conn->connectpath);
596 #if SOFTLINK_OPTIMISATION
597 /* resolve any soft links early */
600 pstrcpy(s,conn->connectpath);
602 string_set(&conn->connectpath,s);
603 vfs_ChDir(conn,conn->connectpath);
607 add_session_user(user);
609 /* execute any "preexec = " line */
610 if (*lp_preexec(SNUM(conn))) {
612 pstrcpy(cmd,lp_preexec(SNUM(conn)));
613 standard_sub_conn(conn,cmd);
614 ret = smbrun(cmd,NULL,False);
615 if (ret != 0 && lp_preexec_close(SNUM(conn))) {
616 DEBUG(1,("preexec gave %d - failing connection\n", ret));
618 *ecode = ERRsrverror;
624 * Print out the 'connected as' stuff here as we need
625 * to know the effective uid and gid we will be using.
628 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
629 dbgtext( "%s (%s) ", remote_machine, conn->client_address );
630 dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
631 dbgtext( "as user %s ", user );
632 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
633 dbgtext( "(pid %d)\n", (int)sys_getpid() );
636 /* we've finished with the sensitive stuff */
639 /* Add veto/hide lists */
640 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
641 set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
642 set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
643 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
646 /* Invoke VFS make connection hook */
648 if (conn->vfs_ops.connect) {
649 if (conn->vfs_ops.connect(conn->vfs_conn, service, user) < 0)
657 /****************************************************************************
659 ****************************************************************************/
660 void close_cnum(connection_struct *conn, uint16 vuid)
662 DirCacheFlush(SNUM(conn));
666 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
667 remote_machine,conn->client_address,
668 lp_servicename(SNUM(conn))));
670 if (conn->vfs_ops.disconnect != NULL) {
672 /* Call VFS disconnect hook */
674 conn->vfs_ops.disconnect();
678 yield_connection(conn,
679 lp_servicename(SNUM(conn)),
680 lp_max_connections(SNUM(conn)));
682 if (lp_status(SNUM(conn)))
683 yield_connection(conn,"",MAXSTATUS);
685 file_close_conn(conn);
686 dptr_closecnum(conn);
688 /* execute any "postexec = " line */
689 if (*lp_postexec(SNUM(conn)) &&
690 become_user(conn, vuid)) {
692 pstrcpy(cmd,lp_postexec(SNUM(conn)));
693 standard_sub_conn(conn,cmd);
694 smbrun(cmd,NULL,False);
699 /* execute any "root postexec = " line */
700 if (*lp_rootpostexec(SNUM(conn))) {
702 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
703 standard_sub_conn(conn,cmd);
704 smbrun(cmd,NULL,False);