/* Group and User RID username mapping function */ BOOL name_to_rid(char *user_name, uint32 *u_rid, uint32 *g_rid) { struct passwd *pw = Get_Pwnam(user_name, False); if (u_rid == NULL || g_rid == NULL || user_name == NULL) { return False; } if (!pw) { DEBUG(1,("Username %s is invalid on this system\n", user_name)); return False; } if (user_in_list(user_name, lp_domain_guest_users())) { *u_rid = DOMAIN_USER_RID_GUEST; } else if (user_in_list(user_name, lp_domain_admin_users())) { *u_rid = DOMAIN_USER_RID_ADMIN; } else { /* turn the unix UID into a Domain RID. this is what the posix sub-system does (adds 1000 to the uid) */ *u_rid = (uint32)(pw->pw_uid + 1000); } /* absolutely no idea what to do about the unix GID to Domain RID mapping */ *g_rid = (uint32)(pw->pw_gid + 1000); return True; }
static bool user_ok(const char *user, int snum) { char **valid, **invalid; bool ret; valid = invalid = NULL; ret = True; if (lp_invalid_users(snum)) { invalid = str_list_copy(talloc_tos(), lp_invalid_users(snum)); if (invalid && str_list_substitute(invalid, "%S", lp_servicename(snum))) { /* This is used in sec=share only, so no current user * around to pass to str_list_sub_basic() */ if ( invalid && str_list_sub_basic(invalid, "", "") ) { ret = !user_in_list(user, (const char **)invalid); } } } TALLOC_FREE(invalid); if (ret && lp_valid_users(snum)) { valid = str_list_copy(talloc_tos(), lp_valid_users(snum)); if ( valid && str_list_substitute(valid, "%S", lp_servicename(snum)) ) { /* This is used in sec=share only, so no current user * around to pass to str_list_sub_basic() */ if ( valid && str_list_sub_basic(valid, "", "") ) { ret = user_in_list(user, (const char **)valid); } } } TALLOC_FREE(valid); if (ret && lp_onlyuser(snum)) { char **user_list = str_list_make_v3( talloc_tos(), lp_username(snum), NULL); if (user_list && str_list_substitute(user_list, "%S", lp_servicename(snum))) { ret = user_in_list(user, (const char **)user_list); } TALLOC_FREE(user_list); } return(ret); }
static BOOL user_ok(const char *user, int snum) { char **valid, **invalid; BOOL ret; valid = invalid = NULL; ret = True; if (lp_invalid_users(snum)) { str_list_copy(&invalid, lp_invalid_users(snum)); if (invalid && str_list_substitute(invalid, "%S", lp_servicename(snum))) { if ( invalid && str_list_sub_basic(invalid, current_user_info.smb_name) ) { ret = !user_in_list(user, (const char **)invalid); } } } if (invalid) str_list_free (&invalid); if (ret && lp_valid_users(snum)) { str_list_copy(&valid, lp_valid_users(snum)); if ( valid && str_list_substitute(valid, "%S", lp_servicename(snum)) ) { if ( valid && str_list_sub_basic(valid, current_user_info.smb_name) ) { ret = user_in_list(user, (const char **)valid); } } } if (valid) str_list_free (&valid); if (ret && lp_onlyuser(snum)) { char **user_list = str_list_make (lp_username(snum), NULL); if (user_list && str_list_substitute(user_list, "%S", lp_servicename(snum))) { ret = user_in_list(user, (const char **)user_list); } if (user_list) str_list_free (&user_list); } return(ret); }
static BOOL is_share_read_only_for_user(connection_struct *conn, user_struct *vuser) { char **list; const char *service = lp_servicename(conn->service); BOOL read_only_ret = lp_readonly(conn->service); if (!service) return read_only_ret; str_list_copy(&list, lp_readlist(conn->service)); if (list) { if (!str_list_sub_basic(list, vuser->user.smb_name) ) { DEBUG(0, ("is_share_read_only_for_user: ERROR: read list substitution failed\n")); } if (!str_list_substitute(list, "%S", service)) { DEBUG(0, ("is_share_read_only_for_user: ERROR: read list service substitution failed\n")); } if (user_in_list(vuser->user.unix_name, (const char **)list, vuser->groups, vuser->n_groups)) { read_only_ret = True; } str_list_free(&list); } str_list_copy(&list, lp_writelist(conn->service)); if (list) { if (!str_list_sub_basic(list, vuser->user.smb_name) ) { DEBUG(0, ("is_share_read_only_for_user: ERROR: write list substitution failed\n")); } if (!str_list_substitute(list, "%S", service)) { DEBUG(0, ("is_share_read_only_for_user: ERROR: write list service substitution failed\n")); } if (user_in_list(vuser->user.unix_name, (const char **)list, vuser->groups, vuser->n_groups)) { read_only_ret = False; } str_list_free(&list); } DEBUG(10,("is_share_read_only_for_user: share %s is %s for unix user %s\n", service, read_only_ret ? "read-only" : "read-write", vuser->user.unix_name )); return read_only_ret; }
static BOOL check_user_ok(connection_struct *conn, user_struct *vuser,int snum) { unsigned int i; struct vuid_cache_entry *ent = NULL; BOOL readonly_share; for (i=0;i<conn->vuid_cache.entries && i< VUID_CACHE_SIZE;i++) { if (conn->vuid_cache.array[i].vuid == vuser->vuid) { ent = &conn->vuid_cache.array[i]; conn->read_only = ent->read_only; conn->admin_user = ent->admin_user; return(True); } } if (!user_ok(vuser->user.unix_name,snum, vuser->groups, vuser->n_groups)) return(False); readonly_share = is_share_read_only_for_user(conn, vuser); if (!readonly_share && !share_access_check(conn, snum, vuser, FILE_WRITE_DATA)) { /* smb.conf allows r/w, but the security descriptor denies * write. Fall back to looking at readonly. */ readonly_share = True; } if (!share_access_check(conn, snum, vuser, readonly_share ? FILE_READ_DATA : FILE_WRITE_DATA)) { return False; } i = conn->vuid_cache.entries % VUID_CACHE_SIZE; if (conn->vuid_cache.entries < VUID_CACHE_SIZE) conn->vuid_cache.entries++; ent = &conn->vuid_cache.array[i]; ent->vuid = vuser->vuid; ent->read_only = readonly_share; if (user_in_list(vuser->user.unix_name ,lp_admin_users(conn->service), vuser->groups, vuser->n_groups)) { ent->admin_user = True; } else { ent->admin_user = False; } conn->read_only = ent->read_only; conn->admin_user = ent->admin_user; return(True); }
/**************************************************************************** check if a username is valid ****************************************************************************/ BOOL user_ok(char *user,int snum) { pstring valid, invalid; BOOL ret; StrnCpy(valid, lp_valid_users(snum), sizeof(pstring)); StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring)); string_sub(valid,"%S",lp_servicename(snum)); string_sub(invalid,"%S",lp_servicename(snum)); ret = !user_in_list(user,invalid); if (ret && valid && *valid) ret = user_in_list(user,valid); if (ret && lp_onlyuser(snum)) { char *user_list = lp_username(snum); string_sub(user_list,"%S",lp_servicename(snum)); ret = user_in_list(user,user_list); } return(ret); }
BOOL map_username(char *user) { static BOOL initialised=False; static fstring last_from,last_to; FILE *f; char *mapfile = lp_username_map(); char *s; pstring buf; BOOL mapped_user = False; if (!*user) return False; if (!*mapfile) return False; if (!initialised) { *last_from = *last_to = 0; initialised = True; } if (strequal(user,last_to)) return False; if (strequal(user,last_from)) { DEBUG(3,("Mapped user %s to %s\n",user,last_to)); fstrcpy(user,last_to); return True; } f = sys_fopen(mapfile,"r"); if (!f) { DEBUG(0,("can't open username map %s\n",mapfile)); return False; } DEBUG(4,("Scanning username map %s\n",mapfile)); while((s=fgets_slash(buf,sizeof(buf),f))!=NULL) { char *unixname = s; char *dosname = strchr(unixname,'='); BOOL return_if_mapped = False; if (!dosname) continue; *dosname++ = 0; while (isspace(*unixname)) unixname++; if ('!' == *unixname) { return_if_mapped = True; unixname++; while (*unixname && isspace(*unixname)) unixname++; } if (!*unixname || strchr("#;",*unixname)) continue; { int l = strlen(unixname); while (l && isspace(unixname[l-1])) { unixname[l-1] = 0; l--; } } if (strchr(dosname,'*') || user_in_list(user,dosname)) { DEBUG(3,("Mapped user %s to %s\n",user,unixname)); mapped_user = True; fstrcpy(last_from,user); sscanf(unixname,"%s",user); fstrcpy(last_to,user); if(return_if_mapped) { fclose(f); return True; } } } fclose(f); /* * Setup the last_from and last_to as an optimization so * that we don't scan the file again for the same user. */ fstrcpy(last_from,user); fstrcpy(last_to,user); return mapped_user; }
/**************************************************************************** make a connection to a service ****************************************************************************/ connection_struct *make_connection(char *service,char *user,char *password, int pwlen, char *dev,uint16 vuid, int *ecode) { int snum; struct passwd *pass = NULL; BOOL guest = False; BOOL force = False; extern int Client; connection_struct *conn; int ret; strlower(service); snum = find_service(service); if (snum < 0) { extern int Client; if (strequal(service,"IPC$")) { DEBUG(3,("refusing IPC connection\n")); *ecode = ERRnoipc; return NULL; } DEBUG(0,("%s (%s) couldn't find service %s\n", remote_machine, client_addr(Client), service)); *ecode = ERRinvnetname; return NULL; } if (strequal(service,HOMES_NAME)) { if (*user && Get_Pwnam(user,True)) { fstring dos_username; fstrcpy(dos_username, user); unix_to_dos(dos_username, True); return(make_connection(dos_username,user,password, pwlen,dev,vuid,ecode)); } if(lp_security() != SEC_SHARE) { if (validated_username(vuid)) { fstring dos_username; fstrcpy(user,validated_username(vuid)); fstrcpy(dos_username, user); unix_to_dos(dos_username, True); return(make_connection(dos_username,user,password,pwlen,dev,vuid,ecode)); } } else { /* Security = share. Try with sesssetup_user * as the username. */ if(*sesssetup_user) { fstring dos_username; fstrcpy(user,sesssetup_user); fstrcpy(dos_username, user); unix_to_dos(dos_username, True); return(make_connection(dos_username,user,password,pwlen,dev,vuid,ecode)); } } } if (!lp_snum_ok(snum) || !check_access(Client, lp_hostsallow(snum), lp_hostsdeny(snum))) { *ecode = ERRaccess; return NULL; } /* you can only connect to the IPC$ service as an ipc device */ if (strequal(service,"IPC$")) pstrcpy(dev,"IPC"); if (*dev == '?' || !*dev) { if (lp_print_ok(snum)) { pstrcpy(dev,"LPT1:"); } else { pstrcpy(dev,"A:"); } } /* if the request is as a printer and you can't print then refuse */ strupper(dev); if (!lp_print_ok(snum) && (strncmp(dev,"LPT",3) == 0)) { DEBUG(1,("Attempt to connect to non-printer as a printer\n")); *ecode = ERRinvdevice; return NULL; } /* lowercase the user name */ strlower(user); /* add it as a possible user name */ add_session_user(service); /* shall we let them in? */ if (!authorise_login(snum,user,password,pwlen,&guest,&force,vuid)) { DEBUG( 2, ( "Invalid username/password for %s\n", service ) ); *ecode = ERRbadpw; return NULL; } conn = conn_new(); if (!conn) { DEBUG(0,("Couldn't find free connection.\n")); *ecode = ERRnoresource; conn_free(conn); return NULL; } /* find out some info about the user */ pass = Get_Pwnam(user,True); if (pass == NULL) { DEBUG(0,( "Couldn't find account %s\n",user)); *ecode = ERRbaduid; conn_free(conn); return NULL; } conn->read_only = lp_readonly(snum); { pstring list; StrnCpy(list,lp_readlist(snum),sizeof(pstring)-1); pstring_sub(list,"%S",service); if (user_in_list(user,list)) conn->read_only = True; StrnCpy(list,lp_writelist(snum),sizeof(pstring)-1); pstring_sub(list,"%S",service); if (user_in_list(user,list)) conn->read_only = False; } /* admin user check */ /* JRA - original code denied admin user if the share was marked read_only. Changed as I don't think this is needed, but old code left in case there is a problem here. */ if (user_in_list(user,lp_admin_users(snum)) #if 0 && !conn->read_only #endif ) { conn->admin_user = True; DEBUG(0,("%s logged in as admin user (root privileges)\n",user)); } else { conn->admin_user = False; } conn->force_user = force; conn->vuid = vuid; conn->uid = pass->pw_uid; conn->gid = pass->pw_gid; safe_strcpy(conn->client_address, client_addr(Client), sizeof(conn->client_address)-1); conn->num_files_open = 0; conn->lastused = time(NULL); conn->service = snum; conn->used = True; conn->printer = (strncmp(dev,"LPT",3) == 0); conn->ipc = (strncmp(dev,"IPC",3) == 0); conn->dirptr = NULL; conn->veto_list = NULL; conn->hide_list = NULL; conn->veto_oplock_list = NULL; string_set(&conn->dirpath,""); string_set(&conn->user,user); /* * If force user is true, then store the * given userid and also the primary groupid * of the user we're forcing. */ if (*lp_force_user(snum)) { struct passwd *pass2; pstring fuser; pstrcpy(fuser,lp_force_user(snum)); /* Allow %S to be used by force user. */ pstring_sub(fuser,"%S",service); pass2 = (struct passwd *)Get_Pwnam(fuser,True); if (pass2) { conn->uid = pass2->pw_uid; conn->gid = pass2->pw_gid; string_set(&conn->user,fuser); fstrcpy(user,fuser); conn->force_user = True; DEBUG(3,("Forced user %s\n",fuser)); } else { DEBUG(1,("Couldn't find user %s\n",fuser)); } } #ifdef HAVE_GETGRNAM /* * If force group is true, then override * any groupid stored for the connecting user. */ if (*lp_force_group(snum)) { struct group *gptr; pstring gname; pstring tmp_gname; BOOL user_must_be_member = False; StrnCpy(tmp_gname,lp_force_group(snum),sizeof(pstring)-1); if (tmp_gname[0] == '+') { user_must_be_member = True; StrnCpy(gname,&tmp_gname[1],sizeof(pstring)-2); } else { StrnCpy(gname,tmp_gname,sizeof(pstring)-1); } /* default service may be a group name */ pstring_sub(gname,"%S",service); gptr = (struct group *)getgrnam(gname); if (gptr) { /* * If the user has been forced and the forced group starts * with a '+', then we only set the group to be the forced * group if the forced user is a member of that group. * Otherwise, the meaning of the '+' would be ignored. */ if (conn->force_user && user_must_be_member) { int i; for (i = 0; gptr->gr_mem[i] != NULL; i++) { if (strcmp(user,gptr->gr_mem[i]) == 0) { conn->gid = gptr->gr_gid; DEBUG(3,("Forced group %s for member %s\n",gname,user)); break; } } } else { conn->gid = gptr->gr_gid; DEBUG(3,("Forced group %s\n",gname)); } } else { DEBUG(1,("Couldn't find group %s\n",gname)); } } #endif /* HAVE_GETGRNAM */ { pstring s; pstrcpy(s,lp_pathname(snum)); standard_sub(conn,s); string_set(&conn->connectpath,s); DEBUG(3,("Connect path is %s\n",s)); } /* groups stuff added by ih */ conn->ngroups = 0; conn->groups = NULL; if (!IS_IPC(conn)) { /* Find all the groups this uid is in and store them. Used by become_user() */ setup_groups(conn->user,conn->uid,conn->gid, &conn->ngroups,&conn->groups); /* check number of connections */ if (!claim_connection(conn, lp_servicename(SNUM(conn)), lp_max_connections(SNUM(conn)), False)) { DEBUG(1,("too many connections - rejected\n")); *ecode = ERRnoresource; conn_free(conn); return NULL; } if (lp_status(SNUM(conn))) claim_connection(conn,"STATUS.", MAXSTATUS,False); } /* IS_IPC */ /* execute any "root preexec = " line */ if (*lp_rootpreexec(SNUM(conn))) { pstring cmd; pstrcpy(cmd,lp_rootpreexec(SNUM(conn))); standard_sub(conn,cmd); DEBUG(5,("cmd=%s\n",cmd)); ret = smbrun(cmd,NULL,False); if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) { DEBUG(1,("preexec gave %d - failing connection\n", ret)); conn_free(conn); *ecode = ERRsrverror; return NULL; } } if (!become_user(conn, conn->vuid)) { DEBUG(0,("Can't become connected user!\n")); if (!IS_IPC(conn)) { yield_connection(conn, lp_servicename(SNUM(conn)), lp_max_connections(SNUM(conn))); if (lp_status(SNUM(conn))) { yield_connection(conn,"STATUS.",MAXSTATUS); } } conn_free(conn); *ecode = ERRbadpw; return NULL; } if (dos_ChDir(conn->connectpath) != 0) { DEBUG(0,("Can't change directory to %s (%s)\n", conn->connectpath,strerror(errno))); unbecome_user(); if (!IS_IPC(conn)) { yield_connection(conn, lp_servicename(SNUM(conn)), lp_max_connections(SNUM(conn))); if (lp_status(SNUM(conn))) yield_connection(conn,"STATUS.",MAXSTATUS); } conn_free(conn); *ecode = ERRinvnetname; return NULL; } string_set(&conn->origpath,conn->connectpath); #if SOFTLINK_OPTIMISATION /* resolve any soft links early */ { pstring s; pstrcpy(s,conn->connectpath); dos_GetWd(s); string_set(&conn->connectpath,s); dos_ChDir(conn->connectpath); } #endif add_session_user(user); /* execute any "preexec = " line */ if (*lp_preexec(SNUM(conn))) { pstring cmd; pstrcpy(cmd,lp_preexec(SNUM(conn))); standard_sub(conn,cmd); ret = smbrun(cmd,NULL,False); if (ret != 0 && lp_preexec_close(SNUM(conn))) { DEBUG(1,("preexec gave %d - failing connection\n", ret)); conn_free(conn); *ecode = ERRsrverror; return NULL; } } /* * Print out the 'connected as' stuff here as we need * to know the effective uid and gid we will be using. */ if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) { dbgtext( "%s (%s) ", remote_machine, conn->client_address ); dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) ); dbgtext( "as user %s ", user ); dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() ); dbgtext( "(pid %d)\n", (int)getpid() ); } /* we've finished with the sensitive stuff */ unbecome_user(); /* Add veto/hide lists */ if (!IS_IPC(conn) && !IS_PRINT(conn)) { set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn))); set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn))); set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn))); } return(conn); }
bool map_username(TALLOC_CTX *ctx, const char *user_in, char **p_user_out) { XFILE *f; char *mapfile = lp_username_map(talloc_tos()); char *s; char buf[512]; bool mapped_user = False; char *cmd = lp_username_map_script(talloc_tos()); *p_user_out = NULL; if (!user_in) return false; /* Initially make a copy of the incoming name. */ *p_user_out = talloc_strdup(ctx, user_in); if (!*p_user_out) { return false; } if (strequal(user_in,get_last_to())) return false; if (strequal(user_in,get_last_from())) { DEBUG(3,("Mapped user %s to %s\n",user_in,get_last_to())); TALLOC_FREE(*p_user_out); *p_user_out = talloc_strdup(ctx, get_last_to()); return true; } if (fetch_map_from_gencache(ctx, user_in, p_user_out)) { return true; } /* first try the username map script */ if ( *cmd ) { char **qlines; char *command = NULL; int numlines, ret, fd; command = talloc_asprintf(ctx, "%s \"%s\"", cmd, user_in); if (!command) { return false; } DEBUG(10,("Running [%s]\n", command)); ret = smbrun(command, &fd); DEBUGADD(10,("returned [%d]\n", ret)); TALLOC_FREE(command); if ( ret != 0 ) { if (fd != -1) close(fd); return False; } numlines = 0; qlines = fd_lines_load(fd, &numlines, 0, ctx); DEBUGADD(10,("Lines returned = [%d]\n", numlines)); close(fd); /* should be either no lines or a single line with the mapped username */ if (numlines && qlines) { DEBUG(3,("Mapped user %s to %s\n", user_in, qlines[0] )); set_last_from_to(user_in, qlines[0]); store_map_in_gencache(ctx, user_in, qlines[0]); TALLOC_FREE(*p_user_out); *p_user_out = talloc_strdup(ctx, qlines[0]); if (!*p_user_out) { return false; } } TALLOC_FREE(qlines); return numlines != 0; } /* ok. let's try the mapfile */ if (!*mapfile) return False; f = x_fopen(mapfile,O_RDONLY, 0); if (!f) { DEBUG(0,("can't open username map %s. Error %s\n",mapfile, strerror(errno) )); return False; } DEBUG(4,("Scanning username map %s\n",mapfile)); while((s=fgets_slash(buf,sizeof(buf),f))!=NULL) { char *unixname = s; char *dosname = strchr_m(unixname,'='); char **dosuserlist; bool return_if_mapped = False; if (!dosname) continue; *dosname++ = 0; unixname = skip_space(unixname); if ('!' == *unixname) { return_if_mapped = True; unixname = skip_space(unixname+1); } if (!*unixname || strchr_m("#;",*unixname)) continue; { int l = strlen(unixname); while (l && isspace((int)unixname[l-1])) { unixname[l-1] = 0; l--; } } /* skip lines like 'user = '******'*') || user_in_list(ctx, user_in, (const char **)dosuserlist)) { DEBUG(3,("Mapped user %s to %s\n",user_in,unixname)); mapped_user = True; set_last_from_to(user_in, unixname); store_map_in_gencache(ctx, user_in, unixname); TALLOC_FREE(*p_user_out); *p_user_out = talloc_strdup(ctx, unixname); if (!*p_user_out) { TALLOC_FREE(dosuserlist); x_fclose(f); return false; } if ( return_if_mapped ) { TALLOC_FREE(dosuserlist); x_fclose(f); return True; } } TALLOC_FREE(dosuserlist); } x_fclose(f); /* * If we didn't successfully map a user in the loop above, * setup the last_from and last_to as an optimization so * that we don't scan the file again for the same user. */ if (!mapped_user) { DEBUG(8, ("The user '%s' has no mapping. " "Skip it next time.\n", user_in)); set_last_from_to(user_in, user_in); store_map_in_gencache(ctx, user_in, user_in); } return mapped_user; }