windows.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package fsdriver
  15. import (
  16. "fmt"
  17. "math/rand"
  18. "path"
  19. "regexp"
  20. "strings"
  21. "syscall"
  22. "yunion.io/x/log"
  23. "yunion.io/x/pkg/errors"
  24. "yunion.io/x/pkg/util/version"
  25. "yunion.io/x/pkg/utils"
  26. "yunion.io/x/onecloud/pkg/apis"
  27. api "yunion.io/x/onecloud/pkg/apis/compute"
  28. "yunion.io/x/onecloud/pkg/cloudcommon/types"
  29. deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
  30. "yunion.io/x/onecloud/pkg/util/fileutils2"
  31. "yunion.io/x/onecloud/pkg/util/netutils2"
  32. "yunion.io/x/onecloud/pkg/util/procutils"
  33. "yunion.io/x/onecloud/pkg/util/seclib2"
  34. "yunion.io/x/onecloud/pkg/util/stringutils2"
  35. "yunion.io/x/onecloud/pkg/util/winutils"
  36. )
  37. const (
  38. ACTIVE_COMPUTER_NAME_KEY = `HKLM\SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName`
  39. COMPUTER_NAME_KEY = `HKLM\SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName`
  40. TCPIP_PARAM_KEY = `HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters`
  41. BOOT_SCRIPT_PATH = "/Windows/System32/GroupPolicy/Machine/Scripts/Startup/cloudboot.bat"
  42. WIN_BOOT_SCRIPT_PATH = "cloudboot"
  43. WIN_TELEGRAF_BINARY_PATH = "/opt/yunion/bin/telegraf.exe"
  44. WIN_TELEGRAF_PATH = "/Program Files/Telegraf"
  45. WIN_QGA_PATH = "/Program Files/Qemu-ga"
  46. )
  47. type SWindowsRootFs struct {
  48. *sGuestRootFsDriver
  49. guestDebugLogPath string
  50. bootScript string
  51. bootScripts map[string]string
  52. }
  53. func NewWindowsRootFs(part IDiskPartition) IRootFsDriver {
  54. seq := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
  55. 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}
  56. suffix := make([]byte, 16)
  57. lenSeq := len(seq)
  58. for i := 0; i < 16; i++ {
  59. suffix[i] = seq[rand.Intn(lenSeq)]
  60. }
  61. return &SWindowsRootFs{
  62. sGuestRootFsDriver: newGuestRootFsDriver(part),
  63. guestDebugLogPath: `%SystemRoot%\mdbg_` + string(suffix),
  64. bootScripts: make(map[string]string),
  65. }
  66. }
  67. func (w *SWindowsRootFs) IsFsCaseInsensitive() bool {
  68. return true
  69. }
  70. func (w *SWindowsRootFs) GetName() string {
  71. return "Windows"
  72. }
  73. func (w *SWindowsRootFs) String() string {
  74. return "WindowsRootFs"
  75. }
  76. func (w *SWindowsRootFs) DeployPublicKey(IDiskPartition, string, *deployapi.SSHKeys) error {
  77. return nil
  78. }
  79. func (w *SWindowsRootFs) RootSignatures() []string {
  80. return []string{
  81. "/program files", "/windows",
  82. "/windows/system32/drivers/etc", "/windows/system32/config",
  83. "/windows/system32/config/sam",
  84. "/windows/system32/config/software",
  85. "/windows/system32/config/system",
  86. }
  87. }
  88. func (w *SWindowsRootFs) GetReleaseInfo(IDiskPartition) *deployapi.ReleaseInfo {
  89. confPath := w.rootFs.GetLocalPath("/windows/system32/config", true)
  90. tool := winutils.NewWinRegTool(confPath)
  91. if tool.CheckPath() {
  92. distro := w.GetName()
  93. version := tool.GetProductName()
  94. curVersion := tool.GetVersion()
  95. arch := w.GetArch(hostCpuArch)
  96. lan := tool.GetInstallLanguage()
  97. return &deployapi.ReleaseInfo{
  98. Distro: distro,
  99. Version: version,
  100. Arch: arch,
  101. Language: lan,
  102. CurrentVersion: curVersion,
  103. }
  104. } else {
  105. return nil
  106. }
  107. }
  108. func (w *SWindowsRootFs) GetLoginAccount(rootFs IDiskPartition, sUser string, defaultRootUser bool, windowsDefaultAdminUser bool) (string, error) {
  109. confPath := w.rootFs.GetLocalPath("/windows/system32/config", true)
  110. tool := winutils.NewWinRegTool(confPath)
  111. tool.CheckPath()
  112. users := tool.GetUsers()
  113. admin := "Administrator"
  114. selUsr := ""
  115. isWin10NonPro := w.IsWindows10NonPro()
  116. // Win10 try not to use Administrator users // Win 10 professional can use Adminsitrator
  117. if _, ok := users[admin]; ok && windowsDefaultAdminUser && !isWin10NonPro && w.GetIRootFsDriver().AllowAdminLogin() {
  118. selUsr = admin
  119. } else {
  120. // Looking for an unlocked user who is not an Administrator
  121. for user, ok := range users {
  122. if !ok {
  123. continue
  124. }
  125. if user != admin {
  126. selUsr = user
  127. }
  128. }
  129. if _, ok := users[admin]; ok && len(selUsr) == 0 {
  130. selUsr = admin
  131. }
  132. }
  133. if selUsr == "" {
  134. return "", fmt.Errorf("no unlocked user")
  135. }
  136. if !users[selUsr] {
  137. // user is locked
  138. tool.UnlockUser(selUsr)
  139. }
  140. return selUsr, nil
  141. }
  142. func (w *SWindowsRootFs) GetArch(hostCpuArch string) string {
  143. if w.rootFs.Exists("/program files (x86)", true) {
  144. return apis.OS_ARCH_X86_64
  145. } else if w.rootFs.Exists("/program files (arm)", true) {
  146. return apis.OS_ARCH_AARCH64
  147. }
  148. if hostCpuArch == apis.OS_ARCH_AARCH32 {
  149. return apis.OS_ARCH_AARCH32
  150. } else {
  151. return apis.OS_ARCH_X86_32
  152. }
  153. }
  154. func (w *SWindowsRootFs) IsWindows10NonPro() bool {
  155. info := w.GetReleaseInfo(nil)
  156. if info != nil && strings.HasPrefix(info.Version, "Windows 10 ") && !strings.HasPrefix(info.Version, "Windows 10 Pro") {
  157. return true
  158. }
  159. return false
  160. }
  161. func (w *SWindowsRootFs) IsOldWindows() bool {
  162. info := w.GetReleaseInfo(nil)
  163. if info != nil && strings.HasPrefix(info.CurrentVersion, "5.") {
  164. return true
  165. }
  166. return false
  167. }
  168. func (w *SWindowsRootFs) GetOs() string {
  169. return "Windows"
  170. }
  171. func (w *SWindowsRootFs) appendGuestBootScript(name, content string) {
  172. w.bootScript += "\r\n" + fmt.Sprintf("start %s", name)
  173. w.bootScripts[name] = content
  174. }
  175. func (w *SWindowsRootFs) regAdd(path, key, val, regType string) string {
  176. return fmt.Sprintf(`REG ADD %s /V "%s" /D "%s" /T %s /F`, path, key, val, regType)
  177. }
  178. func (w *SWindowsRootFs) putGuestScriptContents(spath, content string) error {
  179. contentArr := []string{}
  180. contentLen := len(content)
  181. var j = 0
  182. if content[0] == '\n' {
  183. contentArr = append(contentArr, "")
  184. j += 1
  185. }
  186. for i := 1; i < contentLen; i++ {
  187. if content[i] == '\n' && content[i-1] != '\r' {
  188. contentArr = append(contentArr, content[j:i])
  189. j = i + 1
  190. }
  191. }
  192. if j < contentLen {
  193. contentArr = append(contentArr, content[j:])
  194. } else {
  195. contentArr = append(contentArr, "")
  196. }
  197. content = strings.Join(contentArr, "\r\n")
  198. return w.rootFs.FilePutContents(spath, content, false, true)
  199. }
  200. func (w *SWindowsRootFs) DeployHostname(part IDiskPartition, hostname, domain string) error {
  201. bootScript := strings.Join([]string{
  202. `set HOSTNAME_SCRIPT=%SystemRoot%\hostnamecfg.bat`,
  203. `if exist %HOSTNAME_SCRIPT% (`,
  204. ` call %HOSTNAME_SCRIPT%`,
  205. ` del %HOSTNAME_SCRIPT%`,
  206. `)`,
  207. }, "\r\n")
  208. w.appendGuestBootScript("hostnamecfg", bootScript)
  209. lines := []string{}
  210. for k, v := range map[string]string{
  211. "Hostname": hostname,
  212. "Domain": domain,
  213. "NV Hostname": hostname,
  214. "NV Domain": domain,
  215. } {
  216. lines = append(lines, w.regAdd(TCPIP_PARAM_KEY, k, v, "REG_SZ"))
  217. }
  218. // windows allow a maximal length of 15
  219. // http://support.microsoft.com/kb/909264
  220. if len(hostname) > api.MAX_WINDOWS_COMPUTER_NAME_LENGTH {
  221. hostname = hostname[:api.MAX_WINDOWS_COMPUTER_NAME_LENGTH]
  222. }
  223. lines = append(lines, w.regAdd(ACTIVE_COMPUTER_NAME_KEY, "ComputerName", hostname, "REG_SZ"))
  224. lines = append(lines, w.regAdd(COMPUTER_NAME_KEY, "ComputerName", hostname, "REG_SZ"))
  225. hostScripts := strings.Join(lines, "\r\n")
  226. return w.putGuestScriptContents("/windows/hostnamecfg.bat", hostScripts)
  227. }
  228. func (w *SWindowsRootFs) DeployHosts(part IDiskPartition, hn, domain string, ips []string) error {
  229. var (
  230. ETC_HOSTS = "/windows/system32/drivers/etc/hosts"
  231. oldHf = ""
  232. )
  233. if w.rootFs.Exists(ETC_HOSTS, true) {
  234. oldHfBytes, err := w.rootFs.FileGetContents(ETC_HOSTS, true)
  235. if err != nil {
  236. log.Errorln(err)
  237. return err
  238. }
  239. oldHf = string(oldHfBytes)
  240. }
  241. return w.rootFs.FilePutContents(ETC_HOSTS, fileutils2.FormatHostsFile(oldHf, ips, hn, getHostname(hn, domain)), false, true)
  242. }
  243. func (w *SWindowsRootFs) DeployNetworkingScripts(rootfs IDiskPartition, nics []*types.SServerNic) error {
  244. mainNic, err := netutils2.GetMainNicFromDeployApi(nics)
  245. if err != nil {
  246. return err
  247. }
  248. mainIp := ""
  249. if mainNic != nil {
  250. mainIp = mainNic.Ip
  251. }
  252. mainIp6 := ""
  253. if mainNic != nil {
  254. mainIp6 = mainNic.Ip6
  255. }
  256. bootScript := strings.Join([]string{
  257. `set NETCFG_SCRIPT=%SystemRoot%\netcfg.bat`,
  258. `if exist %NETCFG_SCRIPT% (`,
  259. ` call %NETCFG_SCRIPT%`,
  260. ` del %NETCFG_SCRIPT%`,
  261. `)`,
  262. }, "\r\n")
  263. w.appendGuestBootScript("netcfg", bootScript)
  264. lines := []string{
  265. "@echo off",
  266. w.MakeGuestDebugCmd("netcfg step 1"),
  267. "setlocal enableDelayedExpansion",
  268. `for /f "delims=" %%a in ('getmac /fo csv /nh /v') do (`,
  269. ` set line=%%a&set line=!line:"=,!`,
  270. ` for /f "delims=,,, tokens=1,3" %%b in ("!line!") do (`,
  271. }
  272. hasV6 := false
  273. for _, snic := range nics {
  274. if len(snic.Ip6) > 0 {
  275. hasV6 = true
  276. break
  277. }
  278. }
  279. if hasV6 {
  280. lines = append(lines, ` netsh interface teredo set state disable`)
  281. lines = append(lines, ` netsh interface 6to4 set state state=disabled`)
  282. lines = append(lines, ` netsh interface isatap set state state=disabled`)
  283. lines = append(lines, ` netsh interface ipv6 set privacy disabled store=persistent`)
  284. lines = append(lines, ` netsh interface ipv6 set global randomizeidentifiers=disabled store=persistent`)
  285. }
  286. for _, snic := range nics {
  287. mac := snic.Mac
  288. mac = strings.Replace(strings.ToUpper(mac), ":", "-", -1)
  289. lines = append(lines, fmt.Sprintf(` if "%%%%c" == "%s" (`, mac))
  290. if snic.Mtu > 0 {
  291. lines = append(lines, fmt.Sprintf(` netsh interface ipv4 set subinterface "%%%%b" mtu=%d`, snic.Mtu))
  292. }
  293. if snic.Manual {
  294. if len(snic.Ip) > 0 {
  295. netmask := netutils2.Netlen2Mask(int(snic.Masklen))
  296. cfg := fmt.Sprintf(` netsh interface ip set address "%%%%b" static %s %s`, snic.Ip, netmask)
  297. if len(snic.Gateway) > 0 && snic.Ip == mainIp {
  298. cfg += fmt.Sprintf(" %s", snic.Gateway)
  299. }
  300. lines = append(lines, cfg)
  301. }
  302. if len(snic.Ip6) > 0 {
  303. cfg := fmt.Sprintf(` netsh interface ipv6 add address "%%%%b" %s/%d store=persistent`, snic.Ip6, snic.Masklen6)
  304. lines = append(lines, cfg)
  305. if len(snic.Gateway6) > 0 && snic.Ip6 == mainIp6 {
  306. cfg := fmt.Sprintf(` netsh interface ipv6 add route ::/0 "%%%%b" %s`, snic.Gateway6)
  307. lines = append(lines, cfg)
  308. }
  309. }
  310. routes4 := []netutils2.SRouteInfo{}
  311. routes6 := []netutils2.SRouteInfo{}
  312. routes4, routes6 = netutils2.AddNicRoutes(routes4, routes6, snic, mainIp, mainIp6, len(nics))
  313. for _, r := range routes4 {
  314. lines = append(lines, fmt.Sprintf(` netsh interface ip add route %s/%d %s "%%%%b"`, r.Prefix, r.PrefixLen, r.Gateway.String()))
  315. }
  316. for _, r := range routes6 {
  317. lines = append(lines, fmt.Sprintf(` netsh interface ipv6 add route %s/%d %s "%%%%b"`, r.Prefix, r.PrefixLen, r.Gateway.String()))
  318. }
  319. dns4list, dns6list := netutils2.GetNicDns(snic)
  320. if len(dns4list) > 0 {
  321. lines = append(lines, fmt.Sprintf(
  322. ` netsh interface ip set dns name="%%%%b" source=static addr=%s`, dns4list[0]))
  323. if len(dns4list) > 1 {
  324. for i := 1; i < len(dns4list); i++ {
  325. lines = append(lines, fmt.Sprintf(` netsh interface ip add dns "%%%%b" %s index=%d`, dns4list[i], i+1))
  326. }
  327. }
  328. }
  329. if len(dns6list) > 0 {
  330. lines = append(lines, fmt.Sprintf(
  331. ` netsh interface ipv6 set dns name="%%%%b" source=static addr=%s`, dns6list[0]))
  332. if len(dns6list) > 1 {
  333. for i := 1; i < len(dns6list); i++ {
  334. lines = append(lines, fmt.Sprintf(` netsh interface ip add dns "%%%%b" %s index=%d`, dns6list[i], i+1))
  335. }
  336. }
  337. }
  338. if len(snic.Domain) > 0 && snic.Ip == mainIp {
  339. lines = append(lines, w.regAdd(TCPIP_PARAM_KEY, "SearchList", snic.Domain, "REG_SZ"))
  340. }
  341. } else {
  342. if len(snic.Ip) > 0 {
  343. lines = append(lines, ` netsh interface ip set address "%%b" dhcp`)
  344. lines = append(lines, ` netsh interface ip set dns "%%b" dhcp`)
  345. }
  346. if len(snic.Ip6) > 0 {
  347. cfg := ` netsh interface ipv6 set interface "%%b" routerdiscovery=enabled store=persistent`
  348. lines = append(lines, cfg)
  349. cfg = ` netsh interface ipv6 set interface "%%b" managedaddress=enabled otherstateful=enabled store=persistent`
  350. lines = append(lines, cfg)
  351. }
  352. }
  353. lines = append(lines, ` )`)
  354. }
  355. lines = append(lines, ` )`)
  356. lines = append(lines, `)`)
  357. lines = append(lines, w.MakeGuestDebugCmd("netcfg step 2"))
  358. // lines = append(lines, `netsh advfirewall firewall set rule group=\"remote desktop\" new enable=yes`)
  359. netScript := strings.Join(lines, "\r\n")
  360. return w.putGuestScriptContents("/windows/netcfg.bat", netScript)
  361. }
  362. func (w *SWindowsRootFs) MakeGuestDebugCmd(content string) string {
  363. mark := "============="
  364. content = regexp.MustCompile(`(["^&<>|])`).ReplaceAllString(content, "^$1")
  365. return fmt.Sprintf("echo %s %s %s >> %s", mark, content, mark, w.guestDebugLogPath)
  366. }
  367. func (w *SWindowsRootFs) prependGuestBootScript(content string) {
  368. w.bootScript = content + "\r\n" + w.bootScript
  369. }
  370. func (w *SWindowsRootFs) PrepareFsForTemplate(IDiskPartition) error {
  371. for _, f := range []string{"/Pagefile.sys", "/Hiberfil.sys", "/Swapfile.sys"} {
  372. if w.rootFs.Exists(f, true) {
  373. w.rootFs.Remove(f, true)
  374. }
  375. }
  376. return nil
  377. }
  378. func (w *SWindowsRootFs) CommitChanges(part IDiskPartition) error {
  379. confPath := part.GetLocalPath("/windows/system32/config", true)
  380. tool := winutils.NewWinRegTool(confPath)
  381. tool.CheckPath()
  382. tool.EnableRdp()
  383. tool.ResetUSBProfile()
  384. if w.IsOldWindows() {
  385. // windows prior to windows 2003 should not try to commit changes
  386. return nil
  387. }
  388. tool.InstallGpeditStartScript(WIN_BOOT_SCRIPT_PATH)
  389. bootDir := path.Dir(BOOT_SCRIPT_PATH)
  390. if err := w.rootFs.Mkdir(bootDir, syscall.S_IRUSR|syscall.S_IWUSR|syscall.S_IXUSR, true); err != nil {
  391. return err
  392. }
  393. if err := w.rootFs.FilePutContents(BOOT_SCRIPT_PATH, w.bootScript, false, false); err != nil {
  394. return errors.Wrap(err, "write boot script")
  395. }
  396. for k, v := range w.bootScripts {
  397. if err := w.rootFs.FilePutContents(path.Join(bootDir, fmt.Sprintf("%s.bat", k)), v, false, false); err != nil {
  398. return errors.Wrap(err, "write boot scripts")
  399. }
  400. }
  401. return nil
  402. }
  403. func (w *SWindowsRootFs) ChangeUserPasswd(part IDiskPartition, account, gid, publicKey, password string, isRandomPassword bool) (string, error) {
  404. rinfo := w.GetReleaseInfo(part)
  405. confPath := part.GetLocalPath("/windows/system32/config", true)
  406. tool := winutils.NewWinRegTool(confPath)
  407. tool.CheckPath()
  408. success := false
  409. // symbol ^ is escape character is batch file.
  410. password = strings.ReplaceAll(password, "^", "")
  411. if rinfo != nil && version.GE(rinfo.CurrentVersion, "6.1") {
  412. success = w.deployPublicKeyByGuest(account, password)
  413. } else {
  414. success = tool.ChangePassword(account, password) == nil
  415. }
  416. var (
  417. secret string
  418. err error
  419. )
  420. if success {
  421. if len(publicKey) > 0 {
  422. secret, err = seclib2.EncryptBase64(publicKey, password)
  423. if err != nil {
  424. return "", err
  425. }
  426. } else {
  427. secret, err = utils.EncryptAESBase64(gid, password)
  428. if err != nil {
  429. return "", err
  430. }
  431. }
  432. if rinfo != nil && strings.Contains(rinfo.Version, "Windows XP") {
  433. if len(tool.GetLogontype()) > 0 {
  434. tool.SetLogontype("0x0")
  435. }
  436. }
  437. } else {
  438. log.Errorf("Failed Password %s", account)
  439. }
  440. defUanme := tool.GetDefaultAccount()
  441. if len(defUanme) > 0 && defUanme != account {
  442. tool.SetDefaultAccount(account)
  443. }
  444. return secret, nil
  445. }
  446. func (w *SWindowsRootFs) deployPublicKeyByGuest(uname, passwd string) bool {
  447. if !w.deploySetupCompleteScripts(uname, passwd) {
  448. return false
  449. }
  450. bootScript := strings.Join([]string{
  451. `set CHANGE_PASSWD_SCRIPT=%SystemRoot%\chgpwd.bat`,
  452. `if exist %CHANGE_PASSWD_SCRIPT% (`,
  453. ` call %CHANGE_PASSWD_SCRIPT%`,
  454. ` del %CHANGE_PASSWD_SCRIPT%`,
  455. `)`,
  456. }, "\r\n")
  457. w.appendGuestBootScript("chgpwd", bootScript)
  458. logPath := w.guestDebugLogPath
  459. chksum := stringutils2.GetMD5Hash(passwd + logPath[(len(logPath)-10):])
  460. chgpwdScript := strings.Join([]string{
  461. w.MakeGuestDebugCmd("change password step 1"),
  462. strings.Join([]string{
  463. `%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe`,
  464. ` -executionpolicy bypass %SystemRoot%\chgpwd.ps1`,
  465. fmt.Sprintf(" %s %s %s %s", uname, passwd, chksum, logPath),
  466. }, ""),
  467. `del %SystemRoot%\chgpwd.ps1`,
  468. w.MakeGuestDebugCmd("change password step 2"),
  469. }, "\r\n")
  470. if w.putGuestScriptContents("/windows/chgpwd.bat", chgpwdScript) != nil {
  471. return false
  472. }
  473. if w.putGuestScriptContents("/windows/chgpwd.ps1", WinScriptChangePassword) != nil {
  474. return false
  475. }
  476. return true
  477. }
  478. func (w *SWindowsRootFs) deploySetupCompleteScripts(uname, passwd string) bool {
  479. SETUP_SCRIPT_PATH := "/Windows/Setup/Scripts/SetupComplete.cmd"
  480. if !w.rootFs.Exists(path.Dir(SETUP_SCRIPT_PATH), true) {
  481. w.rootFs.Mkdir(path.Dir(SETUP_SCRIPT_PATH),
  482. syscall.S_IRUSR|syscall.S_IWUSR|syscall.S_IXUSR, true)
  483. }
  484. if w.putGuestScriptContents("/windows/chgpwd_setup.ps1", WinScriptChangePassword) != nil {
  485. return false
  486. }
  487. cmds := []string{
  488. `%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -executionpolicy bypass %SystemRoot%\chgpwd_setup.ps1 ` +
  489. fmt.Sprintf("%s %s", uname, passwd),
  490. "Net stop wuauserv",
  491. }
  492. for _, v := range [][3]string{
  493. {"AUOptions", "REG_DWORD", "3"},
  494. {"NoAutoUpdate", "REG_DWORD", "0"},
  495. {"ScheduledInstallDay", "REG_DWORD", "0"},
  496. {"ScheduledInstallTime", "REG_DWORD", "4"},
  497. {"AutoInstallMinorUpdates", "REG_DWORD", "1"},
  498. {"NoAutoRebootWithLoggedOnUsers", "REG_DWORD", "1"},
  499. {"IncludeRecommendedUpdates", "REG_DWORD", "0"},
  500. {"EnableFeaturedSoftware", "REG_DWORD", "1"},
  501. } {
  502. cmds = append(cmds, fmt.Sprintf(`REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update" /v %s /t %s /d %s /f`,
  503. v[0], v[1], v[2]))
  504. }
  505. cmds = append(cmds, `REG ADD "HKLM\SYSTEM\CurrentControlSet\Control\TimeZoneInformation" /v RealTimeIsUniversal /t REG_DWORD /d 1 /f`)
  506. cmds = append(cmds, "Net start wuauserv")
  507. cmds = append(cmds, "wuauclt /detectnow")
  508. cmds = append(cmds, `del %SystemRoot%\chgpwd_setup.ps1`)
  509. cmds = append(cmds, `del %SystemRoot%\Setup\Scripts\SetupComplete.cmd`)
  510. if w.putGuestScriptContents(SETUP_SCRIPT_PATH, strings.Join(cmds, "\r\n")) != nil {
  511. return false
  512. }
  513. return true
  514. }
  515. func (w *SWindowsRootFs) DeployFstabScripts(rootFs IDiskPartition, disks []*deployapi.Disk) error {
  516. bootScript := strings.Join([]string{
  517. `set MOUNT_DISK_SCRIPT=%SystemRoot%\mountdisk.bat`,
  518. `if exist %MOUNT_DISK_SCRIPT% (`,
  519. ` call %MOUNT_DISK_SCRIPT%`,
  520. ` del %MOUNT_DISK_SCRIPT%`,
  521. `)`,
  522. }, "\r\n")
  523. w.appendGuestBootScript("mountdisk", bootScript)
  524. logPath := w.guestDebugLogPath
  525. mountScript := strings.Join([]string{
  526. w.MakeGuestDebugCmd("mount disk step 1"),
  527. `cscript %SystemRoot%\mountdisk.js --debug ` + logPath,
  528. `del %SystemRoot%\mountdisk.js`,
  529. w.MakeGuestDebugCmd("mount disk step 2"),
  530. }, "\r\n")
  531. if w.putGuestScriptContents("/windows/mountdisk.bat", mountScript) != nil {
  532. return nil
  533. }
  534. w.putGuestScriptContents("/windows/mountdisk.js", WinScriptMountDisk)
  535. return nil
  536. }
  537. func (w *SWindowsRootFs) DetectIsUEFISupport(part IDiskPartition) bool {
  538. content, err := w.rootFs.FileGetContents("/windows/panther/setupact.log", true)
  539. if err != nil {
  540. log.Errorln(err)
  541. return false
  542. }
  543. contentStr := string(content)
  544. sep := "Detected boot environment: "
  545. idx := strings.Index(contentStr, sep)
  546. if idx < 0 {
  547. return false
  548. }
  549. if strings.HasPrefix(contentStr[idx+len(sep):], "EFI") ||
  550. strings.HasPrefix(contentStr[idx+len(sep):], "UEFI") {
  551. return true
  552. }
  553. return false
  554. }
  555. func (l *SWindowsRootFs) IsResizeFsPartitionSupport() bool {
  556. return true
  557. }
  558. func (w *SWindowsRootFs) DeployQgaService(part IDiskPartition) error {
  559. if err := w.rootFs.Mkdir(WIN_QGA_PATH, syscall.S_IRUSR|syscall.S_IWUSR|syscall.S_IXUSR, true); err != nil {
  560. return errors.Wrap(err, "mkdir qemu-ga path")
  561. }
  562. qgaInstallerPath := path.Join(w.rootFs.GetMountPath(), WIN_QGA_PATH, "qemu-ga-x86_64.msi")
  563. output, err := procutils.NewCommand("cp", "-f", QGA_WIN_MSI_INSTALLER_PATH, qgaInstallerPath).Output()
  564. if err != nil {
  565. return errors.Wrapf(err, "cp qga installer failed %s", output)
  566. }
  567. bootScript := strings.Join([]string{
  568. `start "" "%PROGRAMFILES%\Qemu-ga\qemu-ga-x86_64.msi"`,
  569. }, "\r\n")
  570. w.appendGuestBootScript("qemu-ga", bootScript)
  571. return nil
  572. }
  573. func (w *SWindowsRootFs) DeployQgaBlackList(part IDiskPartition) error {
  574. return nil
  575. }
  576. func (w *SWindowsRootFs) DeployTelegraf(config string) (bool, error) {
  577. if err := w.rootFs.Mkdir(WIN_TELEGRAF_PATH, syscall.S_IRUSR|syscall.S_IWUSR|syscall.S_IXUSR, true); err != nil {
  578. return false, errors.Wrap(err, "mkdir telegraf path")
  579. }
  580. telegrafConfPath := path.Join(w.rootFs.GetMountPath(), WIN_TELEGRAF_PATH, "telegraf.conf")
  581. if err := w.rootFs.FilePutContents(telegrafConfPath, config, false, true); err != nil {
  582. return false, errors.Wrap(err, "write boot script")
  583. }
  584. telegrafConfPath = strings.ReplaceAll(path.Join("%PROGRAMFILES%", "Telegraf", "telegraf.conf"), "/", "\\")
  585. telegrafBinaryPath := path.Join(w.rootFs.GetMountPath(), WIN_TELEGRAF_PATH, "telegraf.exe")
  586. output, err := procutils.NewCommand("cp", "-f", WIN_TELEGRAF_BINARY_PATH, telegrafBinaryPath).Output()
  587. if err != nil {
  588. return false, errors.Wrapf(err, "cp telegraf failed %s", output)
  589. }
  590. telegrafBinaryPath = strings.ReplaceAll(path.Join("%PROGRAMFILES%", "Telegraf", "telegraf.exe"), "/", "\\")
  591. bootScript := strings.Join([]string{
  592. `set SETUP_TELEGRAF_SCRIPT=%SystemRoot%\telegraf.bat`,
  593. `if exist %SETUP_TELEGRAF_SCRIPT% (`,
  594. ` call %SETUP_TELEGRAF_SCRIPT%`,
  595. ` del %SETUP_TELEGRAF_SCRIPT%`,
  596. `)`,
  597. }, "\r\n")
  598. w.appendGuestBootScript("telegraf", bootScript)
  599. setupTelegrafBatScript := strings.Join([]string{
  600. w.MakeGuestDebugCmd("setup telegraf step 1"),
  601. strings.Join([]string{
  602. `%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe`,
  603. ` -executionpolicy bypass %SystemRoot%\telegraf.ps1`,
  604. fmt.Sprintf(" '%s' '%s' >> %s_telegraf", telegrafBinaryPath, telegrafConfPath, w.guestDebugLogPath),
  605. }, ""),
  606. `del %SystemRoot%\telegraf.ps1`,
  607. w.MakeGuestDebugCmd("setup telegraf step 2"),
  608. }, "\r\n")
  609. if err := w.putGuestScriptContents("/windows/telegraf.bat", setupTelegrafBatScript); err != nil {
  610. return false, errors.Wrap(err, "put setup bat scirpt")
  611. }
  612. if err := w.putGuestScriptContents("/windows/telegraf.ps1", winTelegrafSetupPowerShellScript); err != nil {
  613. return false, errors.Wrap(err, "put setup ps1 script")
  614. }
  615. return true, nil
  616. }
  617. func (w *SWindowsRootFs) ConfigSshd(loginAccount, loginPassword string, sshPort int) error {
  618. return nil
  619. }