int smb_delete_user_group(const char *unix_group, const char *unix_user) { char *del_script = NULL; int ret = -1; /* defer to scripts */ if ( *lp_deluserfromgroup_script() ) { TALLOC_CTX *ctx = talloc_tos(); del_script = talloc_strdup(ctx, lp_deluserfromgroup_script()); if (!del_script) { return -1; } del_script = talloc_string_sub(ctx, del_script, "%g", unix_group); if (!del_script) { return -1; } del_script = talloc_string_sub(ctx, del_script, "%u", unix_user); if (!del_script) { return -1; } ret = smbrun(del_script,NULL); DEBUG(ret ? 0 : 3,("smb_delete_user_group: Running the command `%s' gave %d\n",del_script,ret)); if (ret == 0) { smb_nscd_flush_group_cache(); } return ret; } return -1; }
static WERROR keyname_to_path(TALLOC_CTX *mem_ctx, const char *keyname, char **path) { char *tmp_path = NULL; if ((keyname == NULL) || (path == NULL)) { return WERR_INVALID_PARAM; } tmp_path = talloc_asprintf(mem_ctx, "\\%s", keyname); if (tmp_path == NULL) { DEBUG(0, ("talloc_asprintf failed!\n")); return WERR_NOMEM; } tmp_path = talloc_string_sub(mem_ctx, tmp_path, "\\", "/"); if (tmp_path == NULL) { DEBUG(0, ("talloc_string_sub_failed!\n")); return WERR_NOMEM; } *path = tmp_path; return WERR_OK; }
static int regdb_normalize_keynames_fn(struct db_record *rec, void *private_data) { TALLOC_CTX *mem_ctx = talloc_tos(); const char *keyname; NTSTATUS status; TDB_DATA key; TDB_DATA value; struct db_context *db = (struct db_context *)private_data; key = dbwrap_record_get_key(rec); if (key.dptr == NULL || key.dsize == 0) { return 0; } value = dbwrap_record_get_value(rec); if (db == NULL) { DEBUG(0, ("regdb_normalize_keynames_fn: ERROR: " "NULL db context handed in via private_data\n")); return 1; } if (strncmp((const char *)key.dptr, REGDB_VERSION_KEYNAME, strlen(REGDB_VERSION_KEYNAME)) == 0) { return 0; } keyname = strchr((const char *)key.dptr, '/'); if (keyname) { keyname = talloc_string_sub(mem_ctx, (const char *)key.dptr, "/", "\\"); DEBUG(2, ("regdb_normalize_keynames_fn: Convert %s to %s\n", (const char *)key.dptr, keyname)); /* Delete the original record and store the normalized key */ status = dbwrap_record_delete(rec); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("regdb_normalize_keynames_fn: " "tdb_delete for [%s] failed!\n", (const char *)key.dptr)); return 1; } status = dbwrap_store_bystring(db, keyname, value, TDB_REPLACE); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("regdb_normalize_keynames_fn: " "failed to store new record for [%s]!\n", keyname)); return 1; } } return 0; }
int smb_create_group(const char *unix_group, gid_t *new_gid) { char *add_script = NULL; int ret = -1; int fd = 0; *new_gid = 0; /* defer to scripts */ if ( *lp_addgroup_script() ) { TALLOC_CTX *ctx = talloc_tos(); add_script = talloc_strdup(ctx, lp_addgroup_script()); if (!add_script) { return -1; } add_script = talloc_string_sub(ctx, add_script, "%g", unix_group); if (!add_script) { return -1; } ret = smbrun(add_script, &fd); DEBUG(ret ? 0 : 3,("smb_create_group: Running the command `%s' gave %d\n",add_script,ret)); if (ret == 0) { smb_nscd_flush_group_cache(); } if (ret != 0) return ret; if (fd != 0) { fstring output; *new_gid = 0; if (read(fd, output, sizeof(output)) > 0) { *new_gid = (gid_t)strtoul(output, NULL, 10); } close(fd); } } if (*new_gid == 0) { struct group *grp = getgrnam(unix_group); if (grp != NULL) *new_gid = grp->gr_gid; } return ret; }
static NTSTATUS log_nt_token(struct security_token *token) { TALLOC_CTX *frame = talloc_stackframe(); char *command; char *group_sidstr; size_t i; if ((lp_log_nt_token_command() == NULL) || (strlen(lp_log_nt_token_command()) == 0)) { TALLOC_FREE(frame); return NT_STATUS_OK; } group_sidstr = talloc_strdup(frame, ""); for (i=1; i<token->num_sids; i++) { group_sidstr = talloc_asprintf( frame, "%s %s", group_sidstr, sid_string_talloc(frame, &token->sids[i])); } command = talloc_string_sub( frame, lp_log_nt_token_command(), "%s", sid_string_talloc(frame, &token->sids[0])); command = talloc_string_sub(frame, command, "%t", group_sidstr); if (command == NULL) { TALLOC_FREE(frame); return NT_STATUS_NO_MEMORY; } DEBUG(8, ("running command: [%s]\n", command)); if (smbrun(command, NULL) != 0) { DEBUG(0, ("Could not log NT token\n")); TALLOC_FREE(frame); return NT_STATUS_ACCESS_DENIED; } TALLOC_FREE(frame); return NT_STATUS_OK; }
NTSTATUS gpo_explode_filesyspath(TALLOC_CTX *mem_ctx, const char *cache_dir, const char *file_sys_path, char **server, char **service, char **nt_path, char **unix_path) { char *path = NULL; *server = NULL; *service = NULL; *nt_path = NULL; *unix_path = NULL; if (!file_sys_path) { return NT_STATUS_OK; } if (!next_token_talloc(mem_ctx, &file_sys_path, server, "\\")) { return NT_STATUS_INVALID_PARAMETER; } NT_STATUS_HAVE_NO_MEMORY(*server); if (!next_token_talloc(mem_ctx, &file_sys_path, service, "\\")) { return NT_STATUS_INVALID_PARAMETER; } NT_STATUS_HAVE_NO_MEMORY(*service); if ((*nt_path = talloc_asprintf(mem_ctx, "\\%s", file_sys_path)) == NULL) { return NT_STATUS_NO_MEMORY; } NT_STATUS_HAVE_NO_MEMORY(*nt_path); if ((path = talloc_asprintf(mem_ctx, "%s/%s", cache_dir, file_sys_path)) == NULL) { return NT_STATUS_NO_MEMORY; } path = talloc_string_sub(mem_ctx, path, "\\", "/"); if (!path) { return NT_STATUS_NO_MEMORY; } *unix_path = talloc_strdup(mem_ctx, path); NT_STATUS_HAVE_NO_MEMORY(*unix_path); talloc_free(path); return NT_STATUS_OK; }
static int regdb_normalize_keynames_fn(struct db_record *rec, void *private_data) { TALLOC_CTX *mem_ctx = talloc_tos(); const char *keyname; NTSTATUS status; if (rec->key.dptr == NULL || rec->key.dsize == 0) { return 0; } keyname = strchr((const char *) rec->key.dptr, '/'); if (keyname) { struct db_record new_rec; keyname = talloc_string_sub(mem_ctx, (const char *) rec->key.dptr, "/", "\\"); DEBUG(2, ("regdb_normalize_keynames_fn: Convert %s to %s\n", (const char *) rec->key.dptr, keyname)); new_rec.value = rec->value; new_rec.key = string_term_tdb_data(keyname); new_rec.private_data = rec->private_data; /* Delete the original record and store the normalized key */ status = rec->delete_rec(rec); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("regdb_normalize_keynames_fn: " "tdb_delete for [%s] failed!\n", rec->key.dptr)); return 1; } status = rec->store(&new_rec, new_rec.value, TDB_REPLACE); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("regdb_normalize_keynames_fn: " "failed to store new record for [%s]!\n", keyname)); return 1; } } return 0; }
/** * Split path into hive name and subkeyname * normalizations performed: * - if the path contains no '\\' characters, * assume that the legacy format of using '/' * as a separator is used and convert '/' to '\\' * - strip trailing '\\' chars */ WERROR split_hive_key(TALLOC_CTX *ctx, const char *path, char **hivename, char **subkeyname) { char *p; const char *tmp_subkeyname; if ((path == NULL) || (hivename == NULL) || (subkeyname == NULL)) { return WERR_INVALID_PARAM; } if (strlen(path) == 0) { return WERR_INVALID_PARAM; } if (strchr(path, '\\') == NULL) { *hivename = talloc_string_sub(ctx, path, "/", "\\"); } else { *hivename = talloc_strdup(ctx, path); } if (*hivename == NULL) { return WERR_NOMEM; } /* strip trailing '\\' chars */ p = strrchr(*hivename, '\\'); while ((p != NULL) && (p[1] == '\0')) { *p = '\0'; p = strrchr(*hivename, '\\'); } p = strchr(*hivename, '\\'); if ((p == NULL) || (*p == '\0')) { /* just the hive - no subkey given */ tmp_subkeyname = ""; } else { *p = '\0'; tmp_subkeyname = p+1; } *subkeyname = talloc_strdup(ctx, tmp_subkeyname); if (*subkeyname == NULL) { return WERR_NOMEM; } return WERR_OK; }
int smb_set_primary_group(const char *unix_group, const char* unix_user) { char *add_script = NULL; int ret = -1; /* defer to scripts */ if ( *lp_setprimarygroup_script() ) { TALLOC_CTX *ctx = talloc_tos(); add_script = talloc_strdup(ctx, lp_setprimarygroup_script()); if (!add_script) { return -1; } add_script = talloc_all_string_sub(ctx, add_script, "%g", unix_group); if (!add_script) { return -1; } add_script = talloc_string_sub(ctx, add_script, "%u", unix_user); if (!add_script) { return -1; } ret = smbrun(add_script,NULL); flush_pwnam_cache(); DEBUG(ret ? 0 : 3,("smb_set_primary_group: " "Running the command `%s' gave %d\n",add_script,ret)); if (ret == 0) { smb_nscd_flush_group_cache(); } return ret; } return -1; }
static NTSTATUS find_forced_user(connection_struct *conn, BOOL vuser_is_guest, fstring username) { int snum = conn->params->service; char *fuser, *found_username; NTSTATUS result; if (!(fuser = talloc_string_sub(conn->mem_ctx, lp_force_user(snum), "%S", lp_servicename(snum)))) { return NT_STATUS_NO_MEMORY; } result = create_token_from_username(conn->mem_ctx, fuser, vuser_is_guest, &conn->uid, &conn->gid, &found_username, &conn->nt_user_token); if (!NT_STATUS_IS_OK(result)) { return result; } fstrcpy(username, found_username); TALLOC_FREE(fuser); TALLOC_FREE(found_username); return NT_STATUS_OK; }
/**************************************************************************** Run a given print command a null terminated list of value/substitute pairs is provided for local substitution strings ****************************************************************************/ static int print_run_command(int snum, const char* printername, bool do_sub, const char *command, int *outfd, ...) { char *syscmd; char *arg; int ret; TALLOC_CTX *ctx = talloc_tos(); va_list ap; va_start(ap, outfd); /* check for a valid system printername and valid command to run */ if ( !printername || !*printername ) { va_end(ap); return -1; } if (!command || !*command) { va_end(ap); return -1; } syscmd = talloc_strdup(ctx, command); if (!syscmd) { va_end(ap); return -1; } while ((arg = va_arg(ap, char *))) { char *value = va_arg(ap,char *); syscmd = talloc_string_sub(ctx, syscmd, arg, value); if (!syscmd) { va_end(ap); return -1; } } va_end(ap); syscmd = talloc_string_sub(ctx, syscmd, "%p", printername); if (!syscmd) { return -1; } if (do_sub && snum != -1) { syscmd = talloc_sub_advanced(ctx, lp_servicename(talloc_tos(), snum), current_user_info.unix_name, "", current_user.ut.gid, get_current_username(), current_user_info.domain, syscmd); if (!syscmd) { return -1; } } ret = smbrun_no_sanitize(syscmd,outfd); DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret)); return ret; }
static int generic_job_submit(int snum, struct printjob *pjob, enum printing_types printing_type, char *lpq_cmd) { int ret = -1; char *current_directory = NULL; char *print_directory = NULL; char *wd = NULL; char *p = NULL; char *jobname = NULL; TALLOC_CTX *ctx = talloc_tos(); fstring job_page_count, job_size; print_queue_struct *q; print_status_struct status; /* we print from the directory path to give the best chance of parsing the lpq output */ wd = sys_getwd(); if (!wd) { return -1; } current_directory = talloc_strdup(ctx, wd); SAFE_FREE(wd); if (!current_directory) { return -1; } print_directory = talloc_strdup(ctx, pjob->filename); if (!print_directory) { return -1; } p = strrchr_m(print_directory,'/'); if (!p) { return -1; } *p++ = 0; if (chdir(print_directory) != 0) { return -1; } jobname = talloc_strdup(ctx, pjob->jobname); if (!jobname) { ret = -1; goto out; } jobname = talloc_string_sub(ctx, jobname, "'", "_"); if (!jobname) { ret = -1; goto out; } slprintf(job_page_count, sizeof(job_page_count)-1, "%d", pjob->page_count); slprintf(job_size, sizeof(job_size)-1, "%lu", (unsigned long)pjob->size); /* send it to the system spooler */ ret = print_run_command(snum, lp_printername(talloc_tos(), snum), True, lp_print_command(talloc_tos(), snum), NULL, "%s", p, "%J", jobname, "%f", p, "%z", job_size, "%c", job_page_count, NULL); if (ret != 0) { ret = -1; goto out; } /* * check the queue for the newly submitted job, this allows us to * determine the backend job identifier (sysjob). */ pjob->sysjob = -1; ret = generic_queue_get(lp_printername(talloc_tos(), snum), printing_type, lpq_cmd, &q, &status); if (ret > 0) { int i; for (i = 0; i < ret; i++) { if (strcmp(q[i].fs_file, p) == 0) { pjob->sysjob = q[i].sysjob; DEBUG(5, ("new job %u (%s) matches sysjob %d\n", pjob->jobid, jobname, pjob->sysjob)); break; } } SAFE_FREE(q); ret = 0; } if (pjob->sysjob == -1) { DEBUG(2, ("failed to get sysjob for job %u (%s), tracking as " "Unix job\n", pjob->jobid, jobname)); } out: if (chdir(current_directory) == -1) { smb_panic("chdir failed in generic_job_submit"); } TALLOC_FREE(current_directory); return ret; }
connection_struct *make_connection_snum(struct smbd_server_connection *sconn, int snum, user_struct *vuser, DATA_BLOB password, const char *pdev, NTSTATUS *pstatus) { connection_struct *conn; struct smb_filename *smb_fname_cpath = NULL; fstring dev; int ret; char addr[INET6_ADDRSTRLEN]; bool on_err_call_dis_hook = false; NTSTATUS status; fstrcpy(dev, pdev); if (NT_STATUS_IS_ERR(*pstatus = share_sanity_checks(snum, dev))) { return NULL; } conn = conn_new(sconn); if (!conn) { DEBUG(0,("Couldn't find free connection.\n")); *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES; return NULL; } conn->params->service = snum; status = create_connection_server_info(sconn, conn, snum, vuser ? vuser->server_info : NULL, password, &conn->server_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("create_connection_server_info failed: %s\n", nt_errstr(status))); *pstatus = status; conn_free(conn); return NULL; } if ((lp_guest_only(snum)) || (lp_security() == SEC_SHARE)) { conn->force_user = true; } add_session_user(sconn, conn->server_info->unix_name); safe_strcpy(conn->client_address, client_addr(get_client_fd(),addr,sizeof(addr)), sizeof(conn->client_address)-1); conn->num_files_open = 0; conn->lastused = conn->lastused_count = time(NULL); conn->used = True; conn->printer = (strncmp(dev,"LPT",3) == 0); conn->ipc = ( (strncmp(dev,"IPC",3) == 0) || ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) ); /* Case options for the share. */ if (lp_casesensitive(snum) == Auto) { /* We will be setting this per packet. Set to be case * insensitive for now. */ conn->case_sensitive = False; } else { conn->case_sensitive = (bool)lp_casesensitive(snum); } conn->case_preserve = lp_preservecase(snum); conn->short_case_preserve = lp_shortpreservecase(snum); conn->encrypt_level = lp_smb_encrypt(snum); conn->veto_list = NULL; conn->hide_list = NULL; conn->veto_oplock_list = NULL; conn->aio_write_behind_list = NULL; conn->read_only = lp_readonly(SNUM(conn)); conn->admin_user = False; if (*lp_force_user(snum)) { /* * Replace conn->server_info with a completely faked up one * from the username we are forced into :-) */ char *fuser; struct auth_serversupplied_info *forced_serverinfo; fuser = talloc_string_sub(conn, lp_force_user(snum), "%S", lp_servicename(snum)); if (fuser == NULL) { conn_free(conn); *pstatus = NT_STATUS_NO_MEMORY; return NULL; } status = make_serverinfo_from_username( conn, fuser, conn->server_info->guest, &forced_serverinfo); if (!NT_STATUS_IS_OK(status)) { conn_free(conn); *pstatus = status; return NULL; } TALLOC_FREE(conn->server_info); conn->server_info = forced_serverinfo; conn->force_user = True; DEBUG(3,("Forced user %s\n", fuser)); } /* * If force group is true, then override * any groupid stored for the connecting user. */ if (*lp_force_group(snum)) { status = find_forced_group( conn->force_user, snum, conn->server_info->unix_name, &conn->server_info->ptok->user_sids[1], &conn->server_info->utok.gid); if (!NT_STATUS_IS_OK(status)) { conn_free(conn); *pstatus = status; return NULL; } /* * We need to cache this gid, to use within * change_to_user() separately from the conn->server_info * struct. We only use conn->server_info directly if * "force_user" was set. */ conn->force_group_gid = conn->server_info->utok.gid; } conn->vuid = (vuser != NULL) ? vuser->vuid : UID_FIELD_INVALID; { char *s = talloc_sub_advanced(talloc_tos(), lp_servicename(SNUM(conn)), conn->server_info->unix_name, conn->connectpath, conn->server_info->utok.gid, conn->server_info->sanitized_username, pdb_get_domain(conn->server_info->sam_account), lp_pathname(snum)); if (!s) { conn_free(conn); *pstatus = NT_STATUS_NO_MEMORY; return NULL; } if (!set_conn_connectpath(conn,s)) { TALLOC_FREE(s); conn_free(conn); *pstatus = NT_STATUS_NO_MEMORY; return NULL; } DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum))); TALLOC_FREE(s); } /* * New code to check if there's a share security descripter * added from NT server manager. This is done after the * smb.conf checks are done as we need a uid and token. JRA. * */ { bool can_write = False; can_write = share_access_check(conn->server_info->ptok, lp_servicename(snum), FILE_WRITE_DATA); if (!can_write) { if (!share_access_check(conn->server_info->ptok, lp_servicename(snum), FILE_READ_DATA)) { /* No access, read or write. */ DEBUG(0,("make_connection: connection to %s " "denied due to security " "descriptor.\n", lp_servicename(snum))); conn_free(conn); *pstatus = NT_STATUS_ACCESS_DENIED; return NULL; } else { conn->read_only = True; } } } /* Initialise VFS function pointers */ if (!smbd_vfs_init(conn)) { DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(snum))); conn_free(conn); *pstatus = NT_STATUS_BAD_NETWORK_NAME; return NULL; } /* * If widelinks are disallowed we need to canonicalise the connect * path here to ensure we don't have any symlinks in the * connectpath. We will be checking all paths on this connection are * below this directory. We must do this after the VFS init as we * depend on the realpath() pointer in the vfs table. JRA. */ if (!lp_widelinks(snum)) { if (!canonicalize_connect_path(conn)) { DEBUG(0, ("canonicalize_connect_path failed " "for service %s, path %s\n", lp_servicename(snum), conn->connectpath)); conn_free(conn); *pstatus = NT_STATUS_BAD_NETWORK_NAME; return NULL; } } if ((!conn->printer) && (!conn->ipc)) { conn->notify_ctx = notify_init(conn, server_id_self(), smbd_messaging_context(), smbd_event_context(), conn); } /* ROOT Activities: */ /* * Enforce the max connections parameter. */ if ((lp_max_connections(snum) > 0) && (count_current_connections(lp_servicename(SNUM(conn)), True) >= lp_max_connections(snum))) { DEBUG(1, ("Max connections (%d) exceeded for %s\n", lp_max_connections(snum), lp_servicename(snum))); conn_free(conn); *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES; return NULL; } /* * Get us an entry in the connections db */ if (!claim_connection(conn, lp_servicename(snum), 0)) { DEBUG(1, ("Could not store connections entry\n")); conn_free(conn); *pstatus = NT_STATUS_INTERNAL_DB_ERROR; return NULL; } /* Preexecs are done here as they might make the dir we are to ChDir * to below */ /* execute any "root preexec = " line */ if (*lp_rootpreexec(snum)) { char *cmd = talloc_sub_advanced(talloc_tos(), lp_servicename(SNUM(conn)), conn->server_info->unix_name, conn->connectpath, conn->server_info->utok.gid, conn->server_info->sanitized_username, pdb_get_domain(conn->server_info->sam_account), lp_rootpreexec(snum)); DEBUG(5,("cmd=%s\n",cmd)); ret = smbrun(cmd,NULL); TALLOC_FREE(cmd); if (ret != 0 && lp_rootpreexec_close(snum)) { DEBUG(1,("root preexec gave %d - failing " "connection\n", ret)); yield_connection(conn, lp_servicename(snum)); conn_free(conn); *pstatus = NT_STATUS_ACCESS_DENIED; return NULL; } } /* USER Activites: */ if (!change_to_user(conn, conn->vuid)) { /* No point continuing if they fail the basic checks */ DEBUG(0,("Can't become connected user!\n")); yield_connection(conn, lp_servicename(snum)); conn_free(conn); *pstatus = NT_STATUS_LOGON_FAILURE; return NULL; } /* Remember that a different vuid can connect later without these * checks... */ /* Preexecs are done here as they might make the dir we are to ChDir * to below */ /* execute any "preexec = " line */ if (*lp_preexec(snum)) { char *cmd = talloc_sub_advanced(talloc_tos(), lp_servicename(SNUM(conn)), conn->server_info->unix_name, conn->connectpath, conn->server_info->utok.gid, conn->server_info->sanitized_username, pdb_get_domain(conn->server_info->sam_account), lp_preexec(snum)); ret = smbrun(cmd,NULL); TALLOC_FREE(cmd); if (ret != 0 && lp_preexec_close(snum)) { DEBUG(1,("preexec gave %d - failing connection\n", ret)); *pstatus = NT_STATUS_ACCESS_DENIED; goto err_root_exit; } } #ifdef WITH_FAKE_KASERVER if (lp_afs_share(snum)) { afs_login(conn); } #endif /* Add veto/hide lists */ if (!IS_IPC(conn) && !IS_PRINT(conn)) { set_namearray( &conn->veto_list, lp_veto_files(snum)); set_namearray( &conn->hide_list, lp_hide_files(snum)); set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum)); set_namearray( &conn->aio_write_behind_list, lp_aio_write_behind(snum)); } /* Invoke VFS make connection hook - do this before the VFS_STAT call to allow any filesystems needing user credentials to initialize themselves. */ if (SMB_VFS_CONNECT(conn, lp_servicename(snum), conn->server_info->unix_name) < 0) { DEBUG(0,("make_connection: VFS make connection failed!\n")); *pstatus = NT_STATUS_UNSUCCESSFUL; goto err_root_exit; } /* Any error exit after here needs to call the disconnect hook. */ on_err_call_dis_hook = true; status = create_synthetic_smb_fname(talloc_tos(), conn->connectpath, NULL, NULL, &smb_fname_cpath); if (!NT_STATUS_IS_OK(status)) { *pstatus = status; goto err_root_exit; } /* win2000 does not check the permissions on the directory during the tree connect, instead relying on permission check during individual operations. To match this behaviour I have disabled this chdir check (tridge) */ /* the alternative is just to check the directory exists */ if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 || !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) { if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) { DEBUG(0,("'%s' is not a directory, when connecting to " "[%s]\n", conn->connectpath, lp_servicename(snum))); } else { DEBUG(0,("'%s' does not exist or permission denied " "when connecting to [%s] Error was %s\n", conn->connectpath, lp_servicename(snum), strerror(errno) )); } *pstatus = NT_STATUS_BAD_NETWORK_NAME; goto err_root_exit; } string_set(&conn->origpath,conn->connectpath); #if SOFTLINK_OPTIMISATION /* resolve any soft links early if possible */ if (vfs_ChDir(conn,conn->connectpath) == 0) { TALLOC_CTX *ctx = talloc_tos(); char *s = vfs_GetWd(ctx,s); if (!s) { *status = map_nt_error_from_unix(errno); goto err_root_exit; } if (!set_conn_connectpath(conn,s)) { *status = NT_STATUS_NO_MEMORY; goto err_root_exit; } vfs_ChDir(conn,conn->connectpath); } #endif if (lp_unix_extensions() && lp_widelinks(snum)) { DEBUG(0,("Share '%s' has wide links and unix extensions enabled. " "These parameters are incompatible. " "Disabling wide links for this share.\n", lp_servicename(snum) )); lp_do_parameter(snum, "wide links", "False"); } /* Figure out the characteristics of the underlying filesystem. This * assumes that all the filesystem mounted withing a share path have * the same characteristics, which is likely but not guaranteed. */ conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res); /* * Print out the 'connected as' stuff here as we need * to know the effective uid and gid we will be using * (at least initially). */ if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) { dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address ); dbgtext( "%s", srv_is_signing_active(smbd_server_conn) ? "signed " : ""); dbgtext( "connect to service %s ", lp_servicename(snum) ); dbgtext( "initially as user %s ", conn->server_info->unix_name ); dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() ); dbgtext( "(pid %d)\n", (int)sys_getpid() ); } /* we've finished with the user stuff - go back to root */ change_to_root_user(); return(conn); err_root_exit: TALLOC_FREE(smb_fname_cpath); change_to_root_user(); if (on_err_call_dis_hook) { /* Call VFS disconnect hook */ SMB_VFS_DISCONNECT(conn); } yield_connection(conn, lp_servicename(snum)); conn_free(conn); return NULL; }
static NTSTATUS find_forced_group(bool force_user, int snum, const char *username, DOM_SID *pgroup_sid, gid_t *pgid) { NTSTATUS result = NT_STATUS_NO_SUCH_GROUP; TALLOC_CTX *frame = talloc_stackframe(); DOM_SID group_sid; enum lsa_SidType type; char *groupname; bool user_must_be_member = False; gid_t gid; groupname = talloc_strdup(talloc_tos(), lp_force_group(snum)); if (groupname == NULL) { DEBUG(1, ("talloc_strdup failed\n")); result = NT_STATUS_NO_MEMORY; goto done; } if (groupname[0] == '+') { user_must_be_member = True; groupname += 1; } groupname = talloc_string_sub(talloc_tos(), groupname, "%S", lp_servicename(snum)); if (groupname == NULL) { DEBUG(1, ("talloc_string_sub failed\n")); result = NT_STATUS_NO_MEMORY; goto done; } if (!lookup_name_smbconf(talloc_tos(), groupname, LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP, NULL, NULL, &group_sid, &type)) { DEBUG(10, ("lookup_name_smbconf(%s) failed\n", groupname)); goto done; } if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) && (type != SID_NAME_WKN_GRP)) { DEBUG(10, ("%s is a %s, not a group\n", groupname, sid_type_lookup(type))); goto done; } if (!sid_to_gid(&group_sid, &gid)) { DEBUG(10, ("sid_to_gid(%s) for %s failed\n", sid_string_dbg(&group_sid), groupname)); goto done; } /* * 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 (force_user && user_must_be_member) { if (user_in_group_sid(username, &group_sid)) { sid_copy(pgroup_sid, &group_sid); *pgid = gid; DEBUG(3,("Forced group %s for member %s\n", groupname, username)); } else { DEBUG(0,("find_forced_group: forced user %s is not a member " "of forced group %s. Disallowing access.\n", username, groupname )); result = NT_STATUS_MEMBER_NOT_IN_GROUP; goto done; } } else { sid_copy(pgroup_sid, &group_sid); *pgid = gid; DEBUG(3,("Forced group %s\n", groupname)); } result = NT_STATUS_OK; done: TALLOC_FREE(frame); return result; }
static int generic_job_submit(int snum, struct printjob *pjob) { int ret = -1; char *current_directory = NULL; char *print_directory = NULL; char *wd = NULL; char *p = NULL; char *jobname = NULL; TALLOC_CTX *ctx = talloc_tos(); fstring job_page_count, job_size; /* we print from the directory path to give the best chance of parsing the lpq output */ wd = sys_getwd(); if (!wd) { return -1; } current_directory = talloc_strdup(ctx, wd); SAFE_FREE(wd); if (!current_directory) { return -1; } print_directory = talloc_strdup(ctx, pjob->filename); if (!print_directory) { return -1; } p = strrchr_m(print_directory,'/'); if (!p) { return -1; } *p++ = 0; if (chdir(print_directory) != 0) { return -1; } jobname = talloc_strdup(ctx, pjob->jobname); if (!jobname) { ret = -1; goto out; } jobname = talloc_string_sub(ctx, jobname, "'", "_"); if (!jobname) { ret = -1; goto out; } slprintf(job_page_count, sizeof(job_page_count)-1, "%d", pjob->page_count); slprintf(job_size, sizeof(job_size)-1, "%lu", (unsigned long)pjob->size); /* send it to the system spooler */ ret = print_run_command(snum, lp_printername(snum), True, lp_printcommand(snum), NULL, "%s", p, "%J", jobname, "%f", p, "%z", job_size, "%c", job_page_count, NULL); out: if (chdir(current_directory) == -1) { smb_panic("chdir failed in generic_job_submit"); } TALLOC_FREE(current_directory); return ret; }
static bool token_contains_name(TALLOC_CTX *mem_ctx, const char *username, const char *domain, const char *sharename, const struct nt_user_token *token, const char *name) { const char *prefix; DOM_SID sid; enum lsa_SidType type; struct smbd_server_connection *sconn = smbd_server_conn; if (username != NULL) { name = talloc_sub_basic(mem_ctx, username, domain, name); } if (sharename != NULL) { name = talloc_string_sub(mem_ctx, name, "%S", sharename); } if (name == NULL) { /* This is too security sensitive, better panic than return a * result that might be interpreted in a wrong way. */ smb_panic("substitutions failed"); } /* check to see is we already have a SID */ if ( string_to_sid( &sid, name ) ) { DEBUG(5,("token_contains_name: Checking for SID [%s] in token\n", name)); return nt_token_check_sid( &sid, token ); } if (!do_group_checks(&name, &prefix)) { if (!lookup_name_smbconf(mem_ctx, name, LOOKUP_NAME_ALL, NULL, NULL, &sid, &type)) { DEBUG(5, ("lookup_name %s failed\n", name)); return False; } if (type != SID_NAME_USER) { DEBUG(5, ("%s is a %s, expected a user\n", name, sid_type_lookup(type))); return False; } return nt_token_check_sid(&sid, token); } for (/* initialized above */ ; *prefix != '\0'; prefix++) { if (*prefix == '+') { if (!lookup_name_smbconf(mem_ctx, name, LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP, NULL, NULL, &sid, &type)) { DEBUG(5, ("lookup_name %s failed\n", name)); return False; } if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) && (type != SID_NAME_WKN_GRP)) { DEBUG(5, ("%s is a %s, expected a group\n", name, sid_type_lookup(type))); return False; } if (nt_token_check_sid(&sid, token)) { return True; } continue; } if (*prefix == '&') { if (username) { if (user_in_netgroup(sconn, username, name)) { return True; } } continue; } smb_panic("got invalid prefix from do_groups_check"); } return False; }
NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum) { NTSTATUS status; if (*lp_force_user(talloc_tos(), snum)) { /* * Replace conn->session_info with a completely faked up one * from the username we are forced into :-) */ char *fuser; char *sanitized_username; struct auth_session_info *forced_serverinfo; bool guest; fuser = talloc_string_sub(conn, lp_force_user(talloc_tos(), snum), "%S", lp_const_servicename(snum)); if (fuser == NULL) { return NT_STATUS_NO_MEMORY; } guest = security_session_user_level(conn->session_info, NULL) < SECURITY_USER; status = make_session_info_from_username( conn, fuser, guest, &forced_serverinfo); if (!NT_STATUS_IS_OK(status)) { return status; } /* We don't want to replace the original sanitized_username as it is the original user given in the connect attempt. This is used in '%U' substitutions. */ sanitized_username = discard_const_p(char, forced_serverinfo->unix_info->sanitized_username); TALLOC_FREE(sanitized_username); forced_serverinfo->unix_info->sanitized_username = talloc_move(forced_serverinfo->unix_info, &conn->session_info->unix_info->sanitized_username); TALLOC_FREE(conn->session_info); conn->session_info = forced_serverinfo; conn->force_user = true; DEBUG(3,("Forced user %s\n", fuser)); } /* * If force group is true, then override * any groupid stored for the connecting user. */ if (*lp_force_group(talloc_tos(), snum)) { status = find_forced_group( conn->force_user, snum, conn->session_info->unix_info->unix_name, &conn->session_info->security_token->sids[1], &conn->session_info->unix_token->gid); if (!NT_STATUS_IS_OK(status)) { return status; } /* * We need to cache this gid, to use within * change_to_user() separately from the conn->session_info * struct. We only use conn->session_info directly if * "force_user" was set. */ conn->force_group_gid = conn->session_info->unix_token->gid; } return NT_STATUS_OK; }
bool authorise_login(int snum, fstring user, DATA_BLOB password, bool *guest) { bool ok = False; #ifdef DEBUG_PASSWORD DEBUG(100,("authorise_login: checking authorisation on " "user=%s pass=%s\n", user,password.data)); #endif *guest = False; /* there are several possibilities: 1) login as the given user with given password 2) login as a previously registered username with the given password 3) login as a session list username with the given password 4) login as a previously validated user/password pair 5) login as the "user ="******"user ="******""); if (!user_list) return(False); for (auser = strtok_r(user_list, LIST_SEP, &saveptr); !ok && auser; auser = strtok_r(NULL, LIST_SEP, &saveptr)) { fstring user2; fstrcpy(user2,auser); if (!user_ok(user2,snum)) continue; if (password_ok(user2,password)) { ok = True; fstrcpy(user,user2); DEBUG(3,("authorise_login: ACCEPTED: session " "list username (%s) and given " "password ok\n", user)); } } SAFE_FREE(user_list); } /* check the user= fields and the given password */ if (!ok && lp_username(snum)) { TALLOC_CTX *ctx = talloc_tos(); char *auser; char *user_list = talloc_strdup(ctx, lp_username(snum)); char *saveptr; if (!user_list) { goto check_guest; } user_list = talloc_string_sub(ctx, user_list, "%S", lp_servicename(snum)); if (!user_list) { goto check_guest; } for (auser = strtok_r(user_list, LIST_SEP, &saveptr); auser && !ok; auser = strtok_r(NULL, LIST_SEP, &saveptr)) { if (*auser == '@') { auser = validate_group(auser+1,password,snum); if (auser) { ok = True; fstrcpy(user,auser); DEBUG(3,("authorise_login: ACCEPTED: " "group username and given " "password ok (%s)\n", user)); } } else { fstring user2; fstrcpy(user2,auser); if (user_ok(user2,snum) && password_ok(user2,password)) { ok = True; fstrcpy(user,user2); DEBUG(3,("authorise_login: ACCEPTED: " "user list username and " "given password ok (%s)\n", user)); } } } } check_guest: /* check for a normal guest connection */ if (!ok && GUEST_OK(snum)) { struct passwd *guest_pw; fstring guestname; fstrcpy(guestname,lp_guestaccount()); guest_pw = Get_Pwnam_alloc(talloc_tos(), guestname); if (guest_pw != NULL) { fstrcpy(user,guestname); ok = True; DEBUG(3,("authorise_login: ACCEPTED: guest account " "and guest ok (%s)\n", user)); } else { DEBUG(0,("authorise_login: Invalid guest account " "%s??\n",guestname)); } TALLOC_FREE(guest_pw); *guest = True; } if (ok && !user_ok(user, snum)) { DEBUG(0,("authorise_login: rejected invalid user %s\n",user)); ok = False; } return(ok); }
bool afs_login(connection_struct *conn) { DATA_BLOB ticket; char *afs_username = NULL; char *cell = NULL; bool result; char *ticket_str = NULL; const struct dom_sid *user_sid; TALLOC_CTX *ctx = talloc_tos(); struct ClearToken ct; afs_username = talloc_strdup(ctx, lp_afs_username_map()); if (!afs_username) { return false; } afs_username = talloc_sub_advanced(ctx, lp_servicename(SNUM(conn)), conn->session_info->unix_info->unix_name, conn->connectpath, conn->session_info->unix_token->gid, conn->session_info->unix_info->sanitized_username, conn->session_info->info->domain_name, afs_username); if (!afs_username) { return false; } user_sid = &conn->session_info->security_token->sids[0]; afs_username = talloc_string_sub(talloc_tos(), afs_username, "%s", sid_string_tos(user_sid)); if (!afs_username) { return false; } /* The pts command always generates completely lower-case user * names. */ strlower_m(afs_username); cell = strchr(afs_username, '@'); if (cell == NULL) { DEBUG(1, ("AFS username doesn't contain a @, " "could not find cell\n")); return false; } *cell = '\0'; cell += 1; DEBUG(10, ("Trying to log into AFS for user %s@%s\n", afs_username, cell)); if (!afs_createtoken(afs_username, cell, &ticket, &ct)) return false; /* For which Unix-UID do we want to set the token? */ ct.ViceId = getuid(); ticket_str = afs_encode_token(cell, ticket, &ct); result = afs_settoken_str(ticket_str); SAFE_FREE(ticket_str); data_blob_free(&ticket); return result; }
static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx, struct tevent_context *ev, struct messaging_context *msg, connection_struct **pconn, int snum, const char *path, const struct auth_session_info *session_info) { connection_struct *conn; char *connpath; const char *vfs_user; struct smbd_server_connection *sconn; const char *servicename = lp_const_servicename(snum); sconn = talloc_zero(ctx, struct smbd_server_connection); if (sconn == NULL) { return NT_STATUS_NO_MEMORY; } sconn->ev_ctx = ev; sconn->msg_ctx = msg; sconn->sock = -1; sconn->smb1.echo_handler.trusted_fd = -1; sconn->smb1.echo_handler.socket_lock_fd = -1; conn = conn_new(sconn); if (conn == NULL) { TALLOC_FREE(sconn); return NT_STATUS_NO_MEMORY; } /* Now we have conn, we need to make sconn a child of conn, * for a proper talloc tree */ talloc_steal(conn, sconn); if (snum == -1 && servicename == NULL) { servicename = "Unknown Service (snum == -1)"; } connpath = talloc_strdup(conn, path); if (!connpath) { TALLOC_FREE(conn); return NT_STATUS_NO_MEMORY; } connpath = talloc_string_sub(conn, connpath, "%S", servicename); if (!connpath) { TALLOC_FREE(conn); return NT_STATUS_NO_MEMORY; } /* needed for smbd_vfs_init() */ conn->params->service = snum; conn->cnum = TID_FIELD_INVALID; if (session_info != NULL) { conn->session_info = copy_session_info(conn, session_info); if (conn->session_info == NULL) { DEBUG(0, ("copy_serverinfo failed\n")); TALLOC_FREE(conn); return NT_STATUS_NO_MEMORY; } vfs_user = conn->session_info->unix_info->unix_name; } else { /* use current authenticated user in absence of session_info */ vfs_user = get_current_username(); } set_conn_connectpath(conn, connpath); /* * New code to check if there's a share security descripter * added from NT server manager. This is done after the * smb.conf checks are done as we need a uid and token. JRA. * */ if (conn->session_info) { share_access_check(conn->session_info->security_token, servicename, MAXIMUM_ALLOWED_ACCESS, &conn->share_access); if ((conn->share_access & FILE_WRITE_DATA) == 0) { if ((conn->share_access & FILE_READ_DATA) == 0) { /* No access, read or write. */ DEBUG(0,("create_conn_struct: connection to %s " "denied due to security " "descriptor.\n", servicename)); conn_free(conn); return NT_STATUS_ACCESS_DENIED; } else { conn->read_only = true; } } } else { conn->share_access = 0; conn->read_only = true; } if (!smbd_vfs_init(conn)) { NTSTATUS status = map_nt_error_from_unix(errno); DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n")); conn_free(conn); return status; } /* this must be the first filesystem operation that we do */ if (SMB_VFS_CONNECT(conn, servicename, vfs_user) < 0) { DEBUG(0,("VFS connect failed!\n")); conn_free(conn); return NT_STATUS_UNSUCCESSFUL; } conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res); *pconn = conn; return NT_STATUS_OK; }