/* * Adds an entry with given DFS name (root sharename) and relative path * to the share (relpath) and the specified entry type (i.e. root/link) * to the namespace cache. */ uint32_t dfs_cache_add_byname(const char *name, const char *relpath, uint32_t type) { char uncpath[DFS_PATH_MAX]; char fspath[DFS_PATH_MAX]; smb_share_t si; if (smb_shr_get((char *)name, &si) != NERR_Success) return (ERROR_NOT_FOUND); if (type == DFS_OBJECT_ROOT) { (void) snprintf(uncpath, DFS_PATH_MAX, "\\\\%s\\%s", dfs_nbname, name); return (dfs_cache_add_byunc(uncpath, si.shr_path, type)); } /* add link entry */ (void) snprintf(fspath, DFS_PATH_MAX, "%s/%s", si.shr_path, relpath); (void) snprintf(uncpath, DFS_PATH_MAX, "\\\\%s\\%s\\%s", dfs_nbname, name, relpath); /* relpath may contain '/' */ (void) strsubst(uncpath, '/', '\\'); return (dfs_cache_add_byunc(uncpath, fspath, type)); }
/*ARGSUSED*/ static void * smbd_share_printers(void *arg) { cups_dest_t *dests; cups_dest_t *dest; smb_cups_ops_t *cups; smb_share_t si; uint32_t nerr; int num_dests; int i; if (!smb_config_getbool(SMB_CI_PRINT_ENABLE)) return (NULL); if ((cups = smbd_cups_ops()) == NULL) return (NULL); if (smb_shr_get(SMB_SHARE_PRINT, &si) != NERR_Success) { syslog(LOG_DEBUG, "smbd_share_printers unable to load %s", SMB_SHARE_PRINT); return (NULL); } num_dests = cups->cupsGetDests(&dests); for (i = num_dests, dest = dests; i > 0; i--, dest++) { if (dest->instance != NULL) continue; (void) strlcpy(si.shr_name, dest->name, MAXPATHLEN); smbd_print_share_comment(&si, dest); si.shr_type = STYPE_PRINTQ; nerr = smb_shr_add(&si); if (nerr == NERR_Success || nerr == NERR_DuplicateShare) syslog(LOG_DEBUG, "shared printer: %s", si.shr_name); else syslog(LOG_DEBUG, "smbd_share_printers: unable to add share %s: %u", si.shr_name, nerr); } cups->cupsFreeDests(num_dests, dests); return (NULL); }
/* * Returns the file system path for the given share if it * is a DFS root share. * If 'path' is NULL, this function only indicates whether * or not the given share represents a DFS namespace */ uint32_t dfs_namespace_path(const char *name, char *path, size_t pathsz) { smb_share_t si; if (smb_shr_get((char *)name, &si) != NERR_Success) return (ERROR_NOT_FOUND); if ((si.shr_flags & SMB_SHRF_DFSROOT) == 0) return (ERROR_NOT_FOUND); if (!dfs_namespace_iscached(name)) return (ERROR_NOT_FOUND); if (path != NULL) (void) strlcpy(path, si.shr_path, pathsz); return (ERROR_SUCCESS); }
/* * Removes the namespace and all the links in it. */ uint32_t dfs_namespace_remove(const char *name) { smb_cache_cursor_t cursor; dfs_nscnode_t nscnode; smb_share_t si; uint32_t status; if (smb_shr_get((char *)name, &si) != NERR_Success) return (ERROR_NOT_FOUND); if ((si.shr_flags & SMB_SHRF_DFSROOT) == 0) return (ERROR_NOT_FOUND); if ((status = dfs_root_remove(si.shr_path)) != ERROR_SUCCESS) return (status); status = srvsvc_shr_setdfsroot(&si, B_FALSE); if (status != ERROR_SUCCESS) syslog(LOG_WARNING, "dfs: failed to disable root share %s (%d)", name, status); if (!dfs_namespace_iscached(name)) return (ERROR_SUCCESS); smb_cache_iterinit(&dfs_nscache, &cursor); while (smb_cache_iterate(&dfs_nscache, &cursor, &nscnode)) { if (nscnode.nsc_type == DFS_OBJECT_ROOT) continue; status = dfs_link_remove(nscnode.nsc_fspath, NULL, NULL); if (status != ERROR_SUCCESS) syslog(LOG_WARNING, "dfs: failed to remove %s (%d)", nscnode.nsc_fspath, status); } dfs_cache_flush(name); /* TODO: remove empty dirs */ return (ERROR_SUCCESS); }
/* * Caches the specified namespace */ static void * dfs_namespace_cache(void *arg) { char *share = arg; char uncpath[DFS_PATH_MAX]; smb_share_t si; if (smb_shr_get(share, &si) != NERR_Success) { free(share); return (NULL); } /* * This check should be removed when multiple standalone * namespaces are supported. */ (void) mutex_lock(&dfs_nsmtx); if (*dfs_cached_ns != '\0') { syslog(LOG_WARNING, "dfs: trying to load %s namespace." " Only one standalone namespace is supported." " A namespace is already exported for %s", share, dfs_cached_ns); (void) mutex_unlock(&dfs_nsmtx); free(share); return (NULL); } (void) strlcpy(dfs_cached_ns, share, sizeof (dfs_cached_ns)); (void) smb_config_setnum(SMB_CI_DFS_STDROOT_NUM, 1); (void) mutex_unlock(&dfs_nsmtx); (void) snprintf(uncpath, DFS_PATH_MAX, "\\\\%s\\%s", dfs_nbname, share); (void) dfs_cache_add_byunc(uncpath, si.shr_path, DFS_OBJECT_ROOT); dfs_cache_populate(uncpath, si.shr_path); free(share); return (NULL); }
/* * GetPrinterData is used t obtain values from the registry for a * printer or a print server. See [MS-RPRN] for value descriptions. * The registry returns ERROR_FILE_NOT_FOUND for unknown keys. */ static int spoolss_s_GetPrinterData(void *arg, ndr_xa_t *mxa) { static spoolss_winreg_t reg[] = { { "ChangeId", 0x0050acf2 }, { "W3SvcInstalled", 0x00000000 }, { "BeepEnabled", 0x00000000 }, { "EventLog", 0x0000001f }, { "NetPopup", 0x00000000 }, { "NetPopupToComputer", 0x00000000 }, { "MajorVersion", 0x00000003 }, { "MinorVersion", 0x00000000 }, { "DsPresent", 0x00000000 } }; struct spoolss_GetPrinterData *param = arg; char *name = (char *)param->pValueName; char buf[MAXPATHLEN]; static uint8_t reserved_buf[4]; spoolss_winreg_t *rp; smb_share_t si; smb_version_t *osversion; struct utsname sysname; smb_wchar_t *wcs; uint32_t value; uint32_t status; int wcslen; int i; if (name == NULL || *name == '\0') { status = ERROR_FILE_NOT_FOUND; goto report_error; } for (i = 0; i < sizeof (reg) / sizeof (reg[0]); ++i) { param->pType = WINREG_DWORD; param->Needed = sizeof (uint32_t); rp = ®[i]; if (strcasecmp(name, rp->name) != 0) continue; if (param->Size < sizeof (uint32_t)) { param->Size = 0; goto need_more_data; } if ((param->Buf = NDR_NEW(mxa, uint32_t)) == NULL) { status = ERROR_NOT_ENOUGH_MEMORY; goto report_error; } value = rp->value; if ((strcasecmp(name, "DsPresent") == 0) && (smb_config_get_secmode() == SMB_SECMODE_DOMAIN)) value = 0x00000001; bcopy(&value, param->Buf, sizeof (uint32_t)); param->Size = sizeof (uint32_t); param->status = ERROR_SUCCESS; return (NDR_DRC_OK); } if (strcasecmp(name, "OSVersion") == 0) { param->pType = WINREG_BINARY; param->Needed = sizeof (smb_version_t); if (param->Size < sizeof (smb_version_t)) { param->Size = sizeof (smb_version_t); goto need_more_data; } if ((osversion = NDR_NEW(mxa, smb_version_t)) == NULL) { status = ERROR_NOT_ENOUGH_MEMORY; goto report_error; } smb_config_get_version(osversion); param->Buf = (uint8_t *)osversion; param->status = ERROR_SUCCESS; return (NDR_DRC_OK); } if (strcasecmp(name, "DNSMachineName") == 0) { param->pType = WINREG_SZ; buf[0] = '\0'; (void) smb_getfqhostname(buf, MAXHOSTNAMELEN); goto encode_string; } if (strcasecmp(name, "DefaultSpoolDirectory") == 0) { param->pType = WINREG_SZ; buf[0] = '\0'; if (smb_shr_get(SMB_SHARE_PRINT, &si) != NERR_Success) { status = ERROR_FILE_NOT_FOUND; goto report_error; } (void) snprintf(buf, MAXPATHLEN, "C:/%s", si.shr_path); (void) strcanon(buf, "/\\"); (void) strsubst(buf, '/', '\\'); goto encode_string; } if (strcasecmp(name, "Architecture") == 0) { param->pType = WINREG_SZ; if (uname(&sysname) < 0) (void) strlcpy(buf, "Solaris", MAXPATHLEN); else (void) snprintf(buf, MAXPATHLEN, "%s %s", sysname.sysname, sysname.machine); goto encode_string; } status = ERROR_FILE_NOT_FOUND; report_error: bzero(param, sizeof (struct spoolss_GetPrinterData)); param->Buf = reserved_buf; param->status = status; return (NDR_DRC_OK); encode_string: wcslen = smb_wcequiv_strlen(buf) + sizeof (smb_wchar_t); if (param->Size < wcslen) { param->Needed = wcslen; goto need_more_data; } if ((wcs = NDR_MALLOC(mxa, wcslen)) == NULL) { status = ERROR_NOT_ENOUGH_MEMORY; goto report_error; } (void) ndr_mbstowcs(NULL, wcs, buf, wcslen); param->Buf = (uint8_t *)wcs; param->Needed = wcslen; param->status = ERROR_SUCCESS; return (NDR_DRC_OK); need_more_data: param->Size = 0; param->Buf = reserved_buf; param->status = ERROR_MORE_DATA; return (NDR_DRC_OK); }
/* * Windows XP and 2000 use this mechanism to write spool files. * Create a spool file fd to be used by spoolss_s_WritePrinter * and add it to the tail of the spool list. */ static int spoolss_s_StartDocPrinter(void *arg, ndr_xa_t *mxa) { struct spoolss_StartDocPrinter *param = arg; ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; smb_spooldoc_t *spfile; spoolss_DocInfo_t *docinfo; char g_path[MAXPATHLEN]; smb_share_t si; int rc; int fd; if (ndr_hdlookup(mxa, id) == NULL) { smb_tracef("spoolss_s_StartDocPrinter: invalid handle"); param->status = ERROR_INVALID_HANDLE; return (NDR_DRC_OK); } if ((docinfo = param->dinfo.DocInfoContainer) == NULL) { param->status = ERROR_INVALID_PARAMETER; return (NDR_DRC_OK); } if ((rc = smb_shr_get(SMB_SHARE_PRINT, &si)) != NERR_Success) { smb_tracef("spoolss_s_StartDocPrinter: %s error=%d", SMB_SHARE_PRINT, rc); param->status = rc; return (NDR_DRC_OK); } if ((spfile = calloc(1, sizeof (smb_spooldoc_t))) == NULL) { param->status = ERROR_NOT_ENOUGH_MEMORY; return (NDR_DRC_OK); } if (docinfo->doc_name != NULL) (void) strlcpy(spfile->sd_doc_name, (char *)docinfo->doc_name, MAXNAMELEN); else (void) strlcpy(spfile->sd_doc_name, "document", MAXNAMELEN); if (docinfo->printer_name != NULL) (void) strlcpy(spfile->sd_printer_name, (char *)docinfo->printer_name, MAXPATHLEN); else (void) strlcpy(spfile->sd_printer_name, "printer", MAXPATHLEN); spfile->sd_ipaddr = mxa->pipe->np_user->ui_ipaddr; (void) strlcpy((char *)spfile->sd_username, mxa->pipe->np_user->ui_account, MAXNAMELEN); (void) memcpy(&spfile->sd_handle, ¶m->handle, sizeof (ndr_hdid_t)); /* * write temporary spool file to print$ */ (void) snprintf(g_path, MAXPATHLEN, "%s/%s%d", si.shr_path, spfile->sd_username, spoolss_cnt); atomic_inc_32(&spoolss_cnt); fd = open(g_path, O_CREAT | O_RDWR, 0600); if (fd == -1) { smb_tracef("spoolss_s_StartDocPrinter: %s: %s", g_path, strerror(errno)); param->status = ERROR_OPEN_FAILED; free(spfile); } else { (void) strlcpy((char *)spfile->sd_path, g_path, MAXPATHLEN); spfile->sd_fd = (uint16_t)fd; /* * Add the document to the spool list. */ (void) rw_wrlock(&spoolss_splist.sp_rwl); list_insert_tail(&spoolss_splist.sp_list, spfile); spoolss_splist.sp_cnt++; (void) rw_unlock(&spoolss_splist.sp_rwl); /* * JobId isn't used now, but if printQ management is added * this will have to be incremented per job submitted. */ param->JobId = 46; param->status = ERROR_SUCCESS; } return (NDR_DRC_OK); }
/* * Creates a DFS root with the given name and comment. * * This function does not create the root share, it * should already exist. */ uint32_t dfs_namespace_add(const char *rootshr, const char *cmnt) { dfs_info_t info; dfs_target_t t; smb_share_t si; uuid_t uuid; uint32_t status; if (*rootshr == '\\') { /* Windows has a special case here! */ return (ERROR_BAD_PATHNAME); } if (smb_shr_get((char *)rootshr, &si) != NERR_Success) return (NERR_NetNameNotFound); (void) mutex_lock(&dfs_nsmtx); if (smb_strcasecmp(dfs_cached_ns, rootshr, 0) == 0) { /* This DFS root is already exported */ (void) mutex_unlock(&dfs_nsmtx); return (ERROR_FILE_EXISTS); } if (*dfs_cached_ns != '\0') { syslog(LOG_WARNING, "dfs: trying to add %s namespace." " Only one standalone namespace is supported." " A namespace is already exported for %s", rootshr, dfs_cached_ns); (void) mutex_unlock(&dfs_nsmtx); return (ERROR_NOT_SUPPORTED); } bzero(&info, sizeof (info)); if (cmnt) (void) strlcpy(info.i_comment, cmnt, sizeof (info.i_comment)); info.i_state = DFS_VOLUME_STATE_OK | DFS_VOLUME_FLAVOR_STANDALONE; info.i_timeout = DFS_ROOT_TIMEOUT; info.i_propflags = 0; uuid_generate_random(uuid); uuid_unparse(uuid, info.i_guid); dfs_target_init(&t, dfs_nbname, rootshr, DFS_STORAGE_STATE_ONLINE); info.i_ntargets = 1; info.i_targets = &t; if ((status = dfs_root_add(si.shr_path, &info)) != ERROR_SUCCESS) { (void) mutex_unlock(&dfs_nsmtx); return (status); } status = srvsvc_shr_setdfsroot(&si, B_TRUE); if (status == ERROR_SUCCESS) { (void) dfs_cache_add_byname(rootshr, NULL, DFS_OBJECT_ROOT); (void) strlcpy(dfs_cached_ns, rootshr, sizeof (dfs_cached_ns)); (void) smb_config_setnum(SMB_CI_DFS_STDROOT_NUM, 1); } (void) mutex_unlock(&dfs_nsmtx); return (status); }