Can you please send us feedback with the [Feedback Hub](https://support.microsoft.com/en-us/windows/send-feedback-to-microsoft-with-the-feedback-hub-app-f59187f8-8739-22d6-ba93-f66612949332) with this issue? Make sure to click the "Start recording" button, then reproduce the issue before submitting the feedback. Once it's submitted, paste the link here so we can more easily find your crash information on the back end?

366 | - addLabel:
367 | label: Needs-Author-Feedback
368 | description:
369 | - if:
370 | - payloadType: Issue_Comment
371 | then:
372 | - cleanEmailReply
373 | description:
374 | - if:
375 | - payloadType: Pull_Request
376 | then:
377 | - labelSync:
378 | pattern: Issue-
379 | - labelSync:
380 | pattern: Area-
381 | - labelSync:
382 | pattern: Priority-
383 | - labelSync:
384 | pattern: Product-
385 | - labelSync:
386 | pattern: Severity-
387 | - labelSync:
388 | pattern: Impact-
389 | description:
390 | - if:
391 | - payloadType: Issue_Comment
392 | - commentContains:
393 | pattern: '\/dup(licate|e)?(\s+of)?\s+https'
394 | isRegex: True
395 | - or:
396 | - activitySenderHasPermission:
397 | permission: Admin
398 | - activitySenderHasPermission:
399 | permission: Write
400 | then:
401 | - addReply:
402 | reply: Hi! We've identified this issue as a duplicate of one that exists on somebody else's Issue Tracker. Please make sure you subscribe to the referenced external issue for future updates. Thanks for your report!
403 | - closeIssue
404 | - removeLabel:
405 | label: Needs-Triage
406 | - addLabel:
407 | label: Resolution-External
408 | - removeLabel:
409 | label: Needs-Attention
410 | - removeLabel:
411 | label: Needs-Author-Feedback
412 | - removeLabel:
413 | label: Needs-Bisect
414 | - removeLabel:
415 | label: Needs-Repro
416 | - removeLabel:
417 | label: Needs-Second
418 | description:
419 | - if:
420 | - payloadType: Issue_Comment
421 | - commentContains:
422 | pattern: /?
423 | isRegex: False
424 | - or:
425 | - activitySenderHasPermission:
426 | permission: Admin
427 | - activitySenderHasPermission:
428 | permission: Write
429 | then:
430 | - removeLabel:
431 | label: Needs-Attention
432 | - addLabel:
433 | label: Needs-Author-Feedback
434 | description:
435 | onFailure:
436 | onSuccess:
--------------------------------------------------------------------------------
/.github/workflows/pr-build.yaml:
--------------------------------------------------------------------------------
1 | name: PR Build & Test
2 |
3 | on:
4 | pull_request:
5 | push:
6 | paths-ignore:
7 | - '.github/ISSUE_TEMPLATE/**'
8 | branches:
9 | - main
10 |
11 | jobs:
12 | check:
13 | runs-on: windows-2022
14 |
15 | strategy:
16 | matrix:
17 | # Apparently ARM targets aren't usable in GH actions
18 | # target: [x86_64-pc-windows-msvc, i686-pc-windows-msvc, aarch64-pc-windows-msvc]
19 | target: [x86_64-pc-windows-msvc, i686-pc-windows-msvc]
20 | branding: [Inbox, Stable, Dev]
21 |
22 | steps:
23 | - name: Checkout
24 | uses: actions/checkout@v4
25 |
26 | - name: Update toolchain
27 | run: rustup update --no-self-update stable && rustup default stable-${{ matrix.target }}
28 |
29 | - name: Add toolchain target
30 | run: rustup target add ${{ matrix.target }}
31 |
32 | - name: Install fmt
33 | run: rustup component add rustfmt
34 |
35 | - name: Install clippy
36 | run: rustup component add clippy
37 |
38 | - name: Fix environment
39 | uses: ./.github/actions/fix-environment
40 |
41 | - name: Clean
42 | run: cargo clean
43 |
44 | - name: Run fmt
45 | run: cargo fmt --all -- --check
46 |
47 | # Test will build the code, then also test it.
48 | - name: Test
49 | run: cargo test --no-default-features --features ${{matrix.branding}} --target ${{ matrix.target }}
50 |
51 | - name: Run clippy
52 | run: cargo clippy --no-default-features --features ${{matrix.branding}} --target ${{matrix.target}} 2>&1
53 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | ARM64/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 | [Ll]og/
25 | objfre/
26 | objchk/
27 |
28 | # Visual Studio 2015 cache/options directory
29 | .vs/
30 |
31 | # Visual Studio Code cache/options directory
32 | .vscode/
33 |
34 | # MSTest test Results
35 | [Tt]est[Rr]esult*/
36 | [Bb]uild[Ll]og.*
37 |
38 | # NUNIT
39 | *.VisualState.xml
40 | TestResult.xml
41 |
42 | # Build Results of an ATL Project
43 | [Dd]ebugPS/
44 | [Rr]eleasePS/
45 | dlldata.c
46 |
47 | # DNX
48 | project.lock.json
49 | artifacts/
50 |
51 | *_h.h
52 | *_i.c
53 | *_p.c
54 | *_i.h
55 | *.ilk
56 | *.meta
57 | *.obj
58 | *.pch
59 | *.pdb
60 | *.pgc
61 | *.pgd
62 | *.rsp
63 | *.sbr
64 | *.tlb
65 | *.tli
66 | *.tlh
67 | *.tmp
68 | *.tmp_proj
69 | *.log
70 | *.vspscc
71 | *.vssscc
72 | .builds
73 | *.pidb
74 | *.svclog
75 | *.scc
76 |
77 | # Chutzpah Test files
78 | _Chutzpah*
79 |
80 | # Visual C++ cache files
81 | ipch/
82 | *.aps
83 | *.ncb
84 | *.opendb
85 | *.opensdf
86 | *.sdf
87 | *.cachefile
88 | *.VC.db
89 | *.VC.VC.opendb
90 |
91 | # Visual Studio profiler
92 | *.psess
93 | *.vsp
94 | *.vspx
95 | *.sap
96 |
97 | # TFS 2012 Local Workspace
98 | $tf/
99 |
100 | # Guidance Automation Toolkit
101 | *.gpState
102 |
103 | # ReSharper is a .NET coding add-in
104 | _ReSharper*/
105 | *.[Rr]e[Ss]harper
106 | *.DotSettings.user
107 |
108 | # JustCode is a .NET coding add-in
109 | .JustCode
110 |
111 | # TeamCity is a build add-in
112 | _TeamCity*
113 |
114 | # DotCover is a Code Coverage Tool
115 | *.dotCover
116 |
117 | # NCrunch
118 | _NCrunch_*
119 | .*crunch*.local.xml
120 | nCrunchTemp_*
121 |
122 | # MightyMoose
123 | *.mm.*
124 | AutoTest.Net/
125 |
126 | # Web workbench (sass)
127 | .sass-cache/
128 |
129 | # Installshield output folder
130 | [Ee]xpress/
131 |
132 | # DocProject is a documentation generator add-in
133 | DocProject/buildhelp/
134 | DocProject/Help/*.HxT
135 | DocProject/Help/*.HxC
136 | DocProject/Help/*.hhc
137 | DocProject/Help/*.hhk
138 | DocProject/Help/*.hhp
139 | DocProject/Help/Html2
140 | DocProject/Help/html
141 |
142 | # Click-Once directory
143 | publish/
144 |
145 | # Publish Web Output
146 | *.[Pp]ublish.xml
147 | *.azurePubxml
148 | # TODO: Comment the next line if you want to check in your web deploy settings
149 | # but database connection strings (with potential passwords) will be unencrypted
150 | *.pubxml
151 | *.publishproj
152 |
153 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
154 | # check in your Azure Web App publish settings, but sensitive information contained
155 | # in these scripts will be unencrypted
156 | PublishScripts/
157 |
158 | # NuGet Packages
159 | *.nupkg
160 | # The packages folder can be ignored because of Package Restore
161 | **/packages/*
162 | # except build/, which is used as an MSBuild target.
163 | !**/packages/build/
164 | # Uncomment if necessary however generally it will be regenerated when needed
165 | #!**/packages/repositories.config
166 | # NuGet v3's project.json files produces more ignorable files
167 | *.nuget.props
168 | *.nuget.targets
169 |
170 | # Microsoft Azure Build Output
171 | csx/
172 | *.build.csdef
173 |
174 | # Microsoft Azure Emulator
175 | ecf/
176 | rcf/
177 |
178 | # Windows Store app package directories and files
179 | AppPackages/
180 | BundleArtifacts/
181 | Package.StoreAssociation.xml
182 | _pkginfo.txt
183 |
184 | # Visual Studio cache files
185 | # files ending in .cache can be ignored
186 | *.[Cc]ache
187 | # but keep track of directories ending in .cache
188 | !*.[Cc]ache/
189 |
190 | # Others
191 | ClientBin/
192 | [Ss]tyle[Cc]op.*
193 | ~$*
194 | *~
195 | *.dbmdl
196 | *.dbproj.schemaview
197 | *.pfx
198 | *.publishsettings
199 | node_modules/
200 | orleans.codegen.cs
201 |
202 | # RIA/Silverlight projects
203 | Generated_Code/
204 |
205 | # Backup & report files from converting an old project file
206 | # to a newer Visual Studio version. Backup files are not needed,
207 | # because we have git ;-)
208 | _UpgradeReport_Files/
209 | Backup*/
210 | UpgradeLog*.XML
211 | UpgradeLog*.htm
212 |
213 | # SQL Server files
214 | *.mdf
215 | *.ldf
216 |
217 | # Business Intelligence projects
218 | *.rdl.data
219 | *.bim.layout
220 | *.bim_*.settings
221 |
222 | # Microsoft Fakes
223 | FakesAssemblies/
224 |
225 | # Node.js Tools for Visual Studio
226 | .ntvs_analysis.dat
227 |
228 | # Visual Studio 6 build log
229 | *.plg
230 |
231 | # Visual Studio 6 workspace options file
232 | *.opt
233 |
234 | # Visual Studio LightSwitch build output
235 | **/*.HTMLClient/GeneratedArtifacts
236 | **/*.DesktopClient/GeneratedArtifacts
237 | **/*.DesktopClient/ModelManifest.xml
238 | **/*.Server/GeneratedArtifacts
239 | **/*.Server/ModelManifest.xml
240 | _Pvt_Extensions
241 |
242 | # Paket dependency manager
243 | .paket/paket.exe
244 | paket-files/
245 |
246 | # FAKE - F# Make
247 | .fake/
248 |
249 | # JetBrains Rider
250 | .idea/
251 | *.sln.iml
252 | *.exe
253 |
254 | # Windows Build System files
255 | build*.dbb
256 | build*.err
257 | build*.evt
258 | build*.log
259 | build*.prf
260 | build*.trc
261 | build*.rec
262 | build*.wrn
263 | build*.metadata
264 |
265 | # MS Build binary logs
266 | *.binlog
267 |
268 | # .razzlerc.cmd file - used by dev environment
269 | tools/.razzlerc.*
270 | # .PowershellModules - if one needs a powershell module dependency, one
271 | # can save it here. used by tools/OpenConsole.psm1
272 | .PowershellModules
273 | # message compiler output
274 | MSG*.bin
275 | /*.exe
276 |
277 | # python
278 | *.pyc
279 |
280 | **/Generated Files/
281 | **/Merged/*
282 | **/Unmerged/*
283 | profiles.json
284 | *.metaproj
285 | *.swp
286 |
287 | launchSettings.json
288 | package-lock.json
289 | draft-*.docx
290 |
291 | **/target/*
292 | # These are backup files generated by rustfmt
293 | **/*.rs.bk
294 |
--------------------------------------------------------------------------------
/.pipelines/OneBranch.Buddy.yml:
--------------------------------------------------------------------------------
1 | #################################################################################
2 | # OneBranch Pipelines - Buddy #
3 | # This pipeline was created by EasyStart from a sample located at: #
4 | # https://aka.ms/obpipelines/easystart/samples #
5 | # Documentation: https://aka.ms/obpipelines #
6 | # Yaml Schema: https://aka.ms/obpipelines/yaml/schema #
7 | # Retail Tasks: https://aka.ms/obpipelines/tasks #
8 | # Support: https://aka.ms/onebranchsup #
9 | #################################################################################
10 |
11 | trigger:
12 | - master
13 |
14 | # Hourly builds: you may want to change these to nightly ("0 3 * * *" - run at 3am).
15 | schedules:
16 | - cron: 0 * * * *
17 | displayName: Hourly build
18 | branches:
19 | include:
20 | - master
21 | always: true
22 |
23 | variables:
24 | CDP_DEFINITION_BUILD_COUNT: $[counter('', 0)] # needed for onebranch.pipeline.version task https://aka.ms/obpipelines/versioning
25 | LinuxContainerImage: 'mcr.microsoft.com/onebranch/cbl-mariner/build:2.0' # Docker image which is used to build the project https://aka.ms/obpipelines/containers
26 | WindowsContainerImage: 'onebranch.azurecr.io/windows/ltsc2019/vse2022:latest'
27 | DEBIAN_FRONTEND: noninteractive
28 |
29 | resources:
30 | repositories:
31 | - repository: templates
32 | type: git
33 | name: OneBranch.Pipelines/GovernedTemplates
34 | ref: refs/heads/main
35 |
36 | extends:
37 | template: v2/OneBranch.NonOfficial.CrossPlat.yml@templates # https://aka.ms/obpipelines/templates
38 | parameters:
39 | cloudvault: # https://aka.ms/obpipelines/cloudvault
40 | enabled: false
41 | globalSdl: # https://aka.ms/obpipelines/sdl
42 | binskim:
43 | # Rust build scripts will not be built with spectre-mitigations enabled, so only scan the actual output binaries.
44 | scanOutputDirectoryOnly: true
45 | stages:
46 | - stage: Build
47 | jobs:
48 | - job: Linux
49 | pool:
50 | type: linux
51 | variables:
52 | ob_outputDirectory: '$(Build.SourcesDirectory)/out' # More settings at https://aka.ms/obpipelines/yaml/jobs
53 | additionalRustTargets: x86_64-unknown-linux-musl
54 | # Cargo's default target dir is $(Build.SourcesDirectory)/target but $(Build.BinariesDirectory)/target is more appropriate.
55 | cargo_target_dir: $(Build.BinariesDirectory)/target
56 | steps:
57 | - template: .pipelines/OneBranch.Common.yml@self
58 |
59 | - job: Windows
60 | pool:
61 | type: windows
62 | variables:
63 | ob_outputDirectory: '$(Build.SourcesDirectory)/out' # More settings at https://aka.ms/obpipelines/yaml/jobs
64 | additionalRustTargets: i686-pc-windows-msvc
65 | # For details on this cargo_target_dir setting, see https://eng.ms/docs/more/rust/topics/onebranch-workaround
66 | cargo_target_dir: C:\cargo_target_dir
67 | steps:
68 | - template: .pipelines/OneBranch.Common.yml@self
69 |
--------------------------------------------------------------------------------
/.pipelines/OneBranch.Common.yml:
--------------------------------------------------------------------------------
1 | # Core build logic that is common to all OneBranch builds.
2 | parameters: # parameters are shown up in ADO UI in a build queue time
3 | - name: buildPlatforms
4 | type: object
5 | default:
6 | - x86_64-pc-windows-msvc # x64
7 | - i686-pc-windows-msvc # x86
8 | - aarch64-pc-windows-msvc # arm64
9 | # - # arm32?
10 |
11 | - name: brandings
12 | type: object
13 | default:
14 | - Inbox
15 | - Stable
16 | - Dev
17 |
18 | - name: tracingGuid
19 | type: string
20 | default: ffffffff-ffff-ffff-ffff-ffffffffffff
21 |
22 | steps:
23 | - task: RustInstaller@1
24 | inputs:
25 | # Can be any "MSRustup" version, such as ms-stable, ms-1.54 or ms-stable-20210513.5 - for more details see https://mscodehub.visualstudio.com/Rust/_git/rust.msrustup
26 | # For supported versions see https://mscodehub.visualstudio.com/Rust/_packaging?_a=package&feed=Rust&view=versions&package=rust.tools-x86_64-pc-windows-msvc&protocolType=NuGet
27 | # We recommend setting this to a specific numbered version such as `ms-1.68` -- we do not recommend
28 | # setting it to `ms-stable`.
29 | # For details on this, see https://eng.ms/docs/more/rust/topics/conventions#toolchain-usage
30 | rustVersion: ms-1.75
31 |
32 | # Space separated list of additional targets: only the host target is supported with the toolchain by default.
33 | #
34 | # This doesn't actually control what gets built - only which toolchains get installed on the build agent.
35 | #
36 | # Theoretically, I could somehow replace this with the buildPlatforms passed in as a parameter
37 | additionalTargets: i686-pc-windows-msvc aarch64-pc-windows-msvc x86_64-pc-windows-msvc
38 |
39 | # URL of an Azure Artifacts feed configured with a crates.io upstream. Must be within the current ADO collection.
40 | # NOTE: Azure Artifacts support for Rust is not yet public, but it is enabled for internal ADO organizations.
41 | # https://learn.microsoft.com/en-us/azure/devops/artifacts/how-to/set-up-upstream-sources?view=azure-devops
42 | cratesIoFeedOverride: sparse+https://pkgs.dev.azure.com/microsoft/Dart/_packaging/sudo_public_cargo/Cargo/index/
43 |
44 | # URL of an Azure Artifacts NuGet feed configured with the mscodehub Rust feed as an upstream.
45 | # * The feed must be within the current ADO collection.
46 | # * The CI account, usually "Project Collection Build Service (org-name)", must have at least "Collaborator" permission.
47 | # When setting up the upstream NuGet feed, use following Azure Artifacts feed locator:
48 | # azure-feed://mscodehub/Rust/Rust@Release
49 | toolchainFeed: https://pkgs.dev.azure.com/microsoft/_packaging/RustTools/nuget/v3/index.json
50 |
51 | displayName: Install Rust toolchain
52 |
53 | # We recommend making a separate `cargo fetch` step, as some build systems
54 | # perform fetching entirely prior to the build, and perform the build with the
55 | # network disabled.
56 | - script: cargo fetch
57 | displayName: Fetch crates
58 |
59 | # First, build and test each branding.
60 | - ${{ each brand in parameters.brandings }}:
61 | - script: cargo build --config .cargo\ms-toolchain-config.toml --no-default-features --features ${{brand}} --frozen 2>&1
62 | displayName: Build ${{brand}} Debug
63 |
64 | - script: cargo test --config .cargo\ms-toolchain-config.toml --no-default-features --features ${{brand}} --frozen 2>&1
65 | displayName: Test ${{brand}} Debug
66 |
67 | # We suggest fmt and clippy after build and test, to catch build breaks and test
68 | # failures as quickly as possible.
69 | # This only needs to happen once, not per-branding.
70 | - script: cargo fmt --check 2>&1
71 | displayName: Check formatting
72 |
73 | - ${{ each brand in parameters.brandings }}:
74 | - script: cargo clippy --config .cargo\ms-toolchain-config.toml --no-default-features --features ${{brand}} --frozen -- -D warnings 2>&1
75 | displayName: Clippy (Linting) ${{brand}}
76 |
77 | # Build release last because it takes the longest and we should have gotten
78 | # all available error signal by this point.
79 | - ${{ each platform in parameters.buildPlatforms }}:
80 | - script: cargo build --config .cargo\ms-toolchain-config.toml --no-default-features --features ${{brand}} --target ${{platform}} --frozen --release 2>&1
81 | env:
82 | MAGIC_TRACING_GUID: ${{ parameters.tracingGuid }}
83 | displayName: Build ${{brand}}-${{platform}} Release
84 |
85 | # At this point, we've completed the build, but each of the outputs is in a
86 | # subdir specific to the architecture being built. That's okay, but the artifact
87 | # drop won't know to look for them in there.
88 | #
89 | # Copy them on out.
90 | - task: CopyFiles@2
91 | displayName: Copy files to output (${{brand}}/${{platform}})
92 | inputs:
93 | sourceFolder: '$(CARGO_TARGET_DIR)/${{platform}}/release'
94 | targetFolder: '$(ob_outputDirectory)/${{brand}}/${{platform}}'
95 | contents: '*'
96 |
97 | # only do this once
98 | - task: CopyFiles@2
99 | displayName: Copy instrumentation manifest to output
100 | inputs:
101 | sourceFolder: 'cpp/logging'
102 | targetFolder: '$(ob_outputDirectory)/'
103 | contents: 'instrumentation.man'
104 |
--------------------------------------------------------------------------------
/.pipelines/PR.Pipeline.yml:
--------------------------------------------------------------------------------
1 | #################################################################################
2 | # OneBranch Pipelines - Buddy #
3 | # This pipeline was created by EasyStart from a sample located at: #
4 | # https://aka.ms/obpipelines/easystart/samples #
5 | # Documentation: https://aka.ms/obpipelines #
6 | # Yaml Schema: https://aka.ms/obpipelines/yaml/schema #
7 | # Retail Tasks: https://aka.ms/obpipelines/tasks #
8 | # Support: https://aka.ms/onebranchsup #
9 | #################################################################################
10 |
11 | trigger: none
12 | # - main
13 |
14 | parameters: # parameters are shown up in ADO UI in a build queue time
15 | # buildPlatforms: This controls which Rust triples we build sudo for.
16 | # These three defaults correspond to x64, x86 and ARM64.
17 | # They're used by:
18 | # - The OneBranch.Common.yml, to control which --target's we build in release
19 | # - The vpack task, below.
20 | - name: buildPlatforms
21 | type: object
22 | default:
23 | - x86_64-pc-windows-msvc # x64
24 | - i686-pc-windows-msvc # x86
25 | - aarch64-pc-windows-msvc # arm64
26 |
27 | # Hourly builds: you may want to change these to nightly ("0 3 * * *" - run at 3am).
28 | schedules:
29 | - cron: 0 * * * *
30 | displayName: Hourly build
31 | branches:
32 | include:
33 | - master
34 | always: true
35 |
36 | variables:
37 | CDP_DEFINITION_BUILD_COUNT: $[counter('', 0)] # needed for onebranch.pipeline.version task https://aka.ms/obpipelines/versioning
38 | WindowsContainerImage: 'onebranch.azurecr.io/windows/ltsc2019/vse2022:latest'
39 |
40 | # LOAD BEARING - the vpack task fails without these
41 | ROOT: $(Build.SourcesDirectory)
42 | REPOROOT: $(Build.SourcesDirectory)
43 | OUTPUTROOT: $(REPOROOT)\out
44 | NUGET_XMLDOC_MODE: none
45 |
46 | resources:
47 | repositories:
48 | - repository: templates
49 | type: git
50 | name: OneBranch.Pipelines/GovernedTemplates
51 | ref: refs/heads/main
52 |
53 | extends:
54 | # We're an official build, so we need to extend from the _Official_ build template.
55 | template: v2/Microsoft.NonOfficial.yml@templates
56 | parameters:
57 | platform:
58 | name: 'windows_undocked'
59 | product: 'sudo'
60 | cloudvault: # https://aka.ms/obpipelines/cloudvault
61 | enabled: false
62 | globalSdl: # https://aka.ms/obpipelines/sdl
63 | binskim:
64 | # Rust build scripts will not be built with spectre-mitigations enabled,
65 | # so only scan the actual output binaries.
66 | scanOutputDirectoryOnly: true
67 | stages:
68 | # Our Build stage will build all three targets in one job, so we don't need
69 | # to repeat most of the boilerplate work in three separate jobs.
70 | - stage: Build
71 | jobs:
72 | - job: Windows
73 | pool:
74 | type: windows
75 |
76 | variables:
77 | # Binaries will go here
78 | ob_outputDirectory: '$(Build.SourcesDirectory)/out' # More settings at https://aka.ms/obpipelines/yaml/jobs
79 | additionalTargets: $(parameters.buildPlatforms)
80 | # For details on this cargo_target_dir setting, see https://eng.ms/docs/more/rust/topics/onebranch-workaround
81 | cargo_target_dir: C:\cargo_target_dir
82 |
83 | # The "standard" pipeline has a bunch of other variables it sets here
84 | # to control vpack creation. However, for a PR build, we don't really
85 | # need any of that.
86 |
87 | steps:
88 | # The actual build is over in Onebranch.Common.yml
89 | - template: .pipelines/OneBranch.Common.yml@self
90 | parameters:
91 | buildPlatforms: ${{ parameters.buildPlatforms }}
92 | # branding will use the default, which is set to build all of them.
93 | # tracingGuid will use the default placeholder for PR builds
94 |
95 | # This is very shamelessly stolen from curl's pipeline. Small
96 | # modification: since our cargo.toml has a bunch of lines with "version",
97 | # bail after the first.
98 | - script: |-
99 | rem Parse the version out of cargo.toml
100 | for /f "tokens=3 delims=- " %%x in ('findstr /c:"version = " sudo\cargo.toml') do (@echo ##vso[task.setvariable variable=SudoVersion]%%~x & goto :EOF)
101 | displayName: 'Set SudoVersion'
102 |
103 | # Codesigning. Cribbed directly from the curl codesign task
104 | - task: onebranch.pipeline.signing@1
105 | displayName: 'Sign files'
106 | inputs:
107 | command: 'sign'
108 | signing_profile: 'external_distribution'
109 | files_to_sign: '**/*.exe'
110 | search_root: '$(ob_outputDirectory)'
111 | use_testsign: false
112 | in_container: true
113 |
--------------------------------------------------------------------------------
/.pipelines/Standard.Pipeline.yml:
--------------------------------------------------------------------------------
1 | #################################################################################
2 | # OneBranch Pipelines - Buddy #
3 | # This pipeline was created by EasyStart from a sample located at: #
4 | # https://aka.ms/obpipelines/easystart/samples #
5 | # Documentation: https://aka.ms/obpipelines #
6 | # Yaml Schema: https://aka.ms/obpipelines/yaml/schema #
7 | # Retail Tasks: https://aka.ms/obpipelines/tasks #
8 | # Support: https://aka.ms/onebranchsup #
9 | #################################################################################
10 |
11 | trigger: none
12 | # - main
13 |
14 | parameters: # parameters are shown up in ADO UI in a build queue time
15 | # buildPlatforms: This controls which Rust triples we build sudo for.
16 | # These three defaults correspond to x64, x86 and ARM64.
17 | # They're used by:
18 | # - The OneBranch.Common.yml, to control which --target's we build in release
19 | # - The vpack task, below.
20 | - name: buildPlatforms
21 | type: object
22 | default:
23 | - x86_64-pc-windows-msvc # x64
24 | - i686-pc-windows-msvc # x86
25 | - aarch64-pc-windows-msvc # arm64
26 |
27 | # The official builds default to just the Inbox builds
28 | - name: brandings
29 | type: object
30 | default:
31 | - Inbox
32 | # - Stable
33 | # - Dev
34 |
35 | # Hourly builds: you may want to change these to nightly ("0 3 * * *" - run at 3am).
36 | schedules:
37 | - cron: 0 * * * *
38 | displayName: Hourly build
39 | branches:
40 | include:
41 | - master
42 | always: true
43 |
44 | variables:
45 | CDP_DEFINITION_BUILD_COUNT: $[counter('', 0)] # needed for onebranch.pipeline.version task https://aka.ms/obpipelines/versioning
46 | WindowsContainerImage: 'onebranch.azurecr.io/windows/ltsc2019/vse2022:latest'
47 |
48 | # LOAD BEARING - the vpack task fails without these
49 | ROOT: $(Build.SourcesDirectory)
50 | REPOROOT: $(Build.SourcesDirectory)
51 | OUTPUTROOT: $(REPOROOT)\out
52 | NUGET_XMLDOC_MODE: none
53 |
54 | resources:
55 | repositories:
56 | - repository: templates
57 | type: git
58 | name: OneBranch.Pipelines/GovernedTemplates
59 | ref: refs/heads/main
60 |
61 | extends:
62 | # We're an official build, so we need to extend from the _Official_ build template.
63 | template: v2/Microsoft.Official.yml@templates
64 | parameters:
65 | platform:
66 | name: 'windows_undocked'
67 | product: 'sudo'
68 | cloudvault: # https://aka.ms/obpipelines/cloudvault
69 | enabled: false
70 | globalSdl: # https://aka.ms/obpipelines/sdl
71 | binskim:
72 | # Rust build scripts will not be built with spectre-mitigations enabled,
73 | # so only scan the actual output binaries.
74 | scanOutputDirectoryOnly: true
75 | stages:
76 | # Our Build stage will build all three targets in one job, so we don't need
77 | # to repeat most of the boilerplate work in three separate jobs.
78 | - stage: Build
79 | jobs:
80 | - job: Windows
81 | pool:
82 | type: windows
83 |
84 | variables:
85 | # Binaries will go here
86 | ob_outputDirectory: '$(Build.SourcesDirectory)/out' # More settings at https://aka.ms/obpipelines/yaml/jobs
87 |
88 | # The vPack gets created from stuff in here
89 | ob_createvpack_vpackdirectory: '$(ob_outputDirectory)/vpack'
90 | # It will have a structure like:
91 | # .../vpack/
92 | # - amd64/
93 | # - sudo.exe
94 | # - i386/
95 | # - sudo.exe
96 | # - arm64/
97 | # - sudo.exe
98 |
99 | # not sure where this goes
100 | # additionalRustTargets: i686-pc-windows-msvc
101 | additionalTargets: $(parameters.buildPlatforms)
102 |
103 | # For details on this cargo_target_dir setting, see https://eng.ms/docs/more/rust/topics/onebranch-workaround
104 | cargo_target_dir: C:\cargo_target_dir
105 |
106 | # All these? Also variables that control the vpack creation.
107 | ob_createvpack_enabled: true
108 | ob_createvpack_packagename: 'windows_sudo.$(Build.SourceBranchName)'
109 | ob_createvpack_owneralias: 'migrie@microsoft.com'
110 | ob_createvpack_description: 'Sudo for Windows'
111 | ob_createvpack_targetDestinationDirectory: '$(Destination)'
112 | ob_createvpack_propsFile: false
113 | ob_createvpack_provData: true
114 | ob_createvpack_versionAs: string
115 | ob_createvpack_version: '$(SudoVersion)-$(CDP_DEFINITION_BUILD_COUNT)'
116 | ob_createvpack_metadata: '$(Build.SourceVersion)'
117 | ob_createvpack_topLevelRetries: 0
118 | ob_createvpack_failOnStdErr: true
119 | ob_createvpack_taskLogVerbosity: Detailed
120 | ob_createvpack_verbose: true
121 |
122 | steps:
123 | # Before we build! Right before we build, pull down localizations from
124 | # Touchdown.
125 | #
126 | # The Terminal build would literally pass this as a parameter of a list
127 | # of steps to the job-build-project.yml, which is overkill for us
128 | - template: .pipelines/steps-fetch-and-prepare-localizations.yml@self
129 | parameters:
130 | includePseudoLoc: true
131 |
132 | # The actual build is over in Onebranch.Common.yml
133 | - template: .pipelines/OneBranch.Common.yml@self
134 | parameters:
135 | buildPlatforms: ${{ parameters.buildPlatforms }}
136 | brandings: ${{ parameters.brandings }}
137 | tracingGuid: $(SecretTracingGuid)
138 |
139 | # This is very shamelessly stolen from curl's pipeline. Small
140 | # modification: since our cargo.toml has a bunch of lines with "version",
141 | # bail after the first.
142 | - script: |-
143 | rem Parse the version out of cargo.toml
144 | for /f "tokens=3 delims=- " %%x in ('findstr /c:"version = " sudo\cargo.toml') do (@echo ##vso[task.setvariable variable=SudoVersion]%%~x & goto :EOF)
145 | displayName: 'Set SudoVersion'
146 |
147 | # Codesigning. Cribbed directly from the curl codesign task
148 | - task: onebranch.pipeline.signing@1
149 | displayName: 'Sign files'
150 | inputs:
151 | command: 'sign'
152 | signing_profile: 'external_distribution'
153 | files_to_sign: '**/*.exe'
154 | search_root: '$(ob_outputDirectory)'
155 | use_testsign: false
156 | in_container: true
157 |
158 | # This stage grabs each of the sudo's we've built for different
159 | # architectures, and copies them into the appropriate vpack directory.
160 | - ${{ each platform in parameters.buildPlatforms }}:
161 | - task: CopyFiles@2
162 | displayName: Copy files to vpack (${{platform}})
163 | inputs:
164 | # We always use the 'Inbox' branding vvvvv here - vpacks are only ever consumed by the OS
165 | sourceFolder: '$(ob_outputDirectory)/Inbox/${{platform}}'
166 | ${{ if eq(platform, 'i686-pc-windows-msvc') }}:
167 | targetFolder: '$(ob_createvpack_vpackdirectory)/i386'
168 | ${{ elseif eq(platform, 'x86_64-pc-windows-msvc') }}:
169 | targetFolder: '$(ob_createvpack_vpackdirectory)/amd64'
170 | ${{ else }}: # aarch64-pc-windows-msvc
171 | targetFolder: '$(ob_createvpack_vpackdirectory)/arm64'
172 | contents: '*'
173 | - task: CopyFiles@2
174 | # only do this once
175 | displayName: Copy manifest to vpack
176 | inputs:
177 | sourceFolder: '$(ob_outputDirectory)/'
178 | targetFolder: '$(ob_createvpack_vpackdirectory)/'
179 | contents: 'instrumentation.man'
180 |
--------------------------------------------------------------------------------
/.pipelines/daily-loc-build.yml:
--------------------------------------------------------------------------------
1 | trigger: none
2 | pr: none
3 | schedules:
4 | - cron: "0 3 * * 2-6" # Run at 03:00 UTC Tuesday through Saturday (After the work day in Pacific, Mon-Fri)
5 | displayName: "Nightly Localization Build"
6 | branches:
7 | include:
8 | - main
9 | always: false # only run if there's code changes!
10 |
11 | pool:
12 | vmImage: windows-2022
13 |
14 | resources:
15 | repositories:
16 | - repository: self
17 | type: git
18 | ref: main
19 |
20 | steps:
21 |
22 | - checkout: self
23 | clean: true
24 | submodules: false
25 | fetchDepth: 1 # Don't need a deep checkout for loc files!
26 | fetchTags: false # Tags still result in depth > 1 fetch; we don't need them here
27 | persistCredentials: true
28 |
29 | - task: MicrosoftTDBuild.tdbuild-task.tdbuild-task.TouchdownBuildTask@3
30 | displayName: 'Touchdown Build - 92350, PRODEXT'
31 | inputs:
32 | teamId: 92350
33 | TDBuildServiceConnection: $(TouchdownServiceConnection)
34 | authType: SubjectNameIssuer
35 | resourceFilePath: |
36 | **\en-US\*.resw
37 | outputDirectoryRoot: LocOutput
38 | appendRelativeDir: true
39 | pseudoSetting: Included
40 |
41 | # Saving one of these makes it really easy to inspect the loc output...
42 | - powershell: 'tar czf LocOutput.tar.gz LocOutput'
43 | displayName: 'Archive Loc Output for Submission'
44 |
45 | - task: PublishBuildArtifacts@1
46 | displayName: 'Publish Artifact: LocOutput'
47 | inputs:
48 | PathtoPublish: LocOutput.tar.gz
49 | ArtifactName: LocOutput
50 |
--------------------------------------------------------------------------------
/.pipelines/steps-fetch-and-prepare-localizations.yml:
--------------------------------------------------------------------------------
1 | parameters:
2 | - name: includePseudoLoc
3 | type: boolean
4 | default: true
5 |
6 | steps:
7 | - task: TouchdownBuildTask@3
8 | displayName: Download Localization Files
9 | inputs:
10 | teamId: 92350
11 | TDBuildServiceConnection: $(TouchdownServiceConnection)
12 | authType: SubjectNameIssuer
13 | resourceFilePath: |
14 | **\en-US\*.resw
15 | appendRelativeDir: true
16 | localizationTarget: false
17 | ${{ if eq(parameters.includePseudoLoc, true) }}:
18 | pseudoSetting: Included
19 |
20 | - pwsh: |-
21 | $Files = Get-ChildItem . -R -Filter 'Resources.resw' | ? FullName -Like '*en-US\*\Resources.resw'
22 | $Files | % { Move-Item -Verbose $_.Directory $_.Directory.Parent.Parent -EA:Ignore }
23 | displayName: Move Loc files into final locations
24 |
--------------------------------------------------------------------------------
/Building.md:
--------------------------------------------------------------------------------
1 | # Building Sudo for Windows
2 |
3 | Sudo for Windows is a Rust project. If you're new to Rust, you can get started with the [Rust Book](https://doc.rust-lang.org/book/). You can quickly get started with rust by installing and running `rustup`:
4 |
5 | ```cmd
6 | winget install --id Rustlang.rustup --source winget
7 | rustup update
8 | ```
9 |
10 | ## Building
11 |
12 | Rust is nice and straightforward. You can build sudo for the default architecture with a simple
13 |
14 | ```
15 | cargo build
16 | ```
17 |
18 | You may want to specify a specific architecture. To do that, you'll want instead:
19 |
20 | ```
21 | cargo build --target x86_64-pc-windows-msvc
22 | ```
23 |
24 | (You can also use `i686-pc-windows-msvc` as the target).
25 |
26 | ### Running tests
27 |
28 | Assuming that you passed a target architecture above:
29 |
30 | ```
31 | cargo test --target x86_64-pc-windows-msvc
32 | ```
33 |
34 | We have additional manual tests that you can use to validate sudo in the
35 | `tools\tests.ipynb` notebook.
36 |
37 | ### Formatting and clippy
38 |
39 | ```
40 | cargo fmt
41 | cargo clippy
42 | ```
43 |
44 | If your code passes a `cargo build && cargo test && cargo fmt && cargo clippy`, you're ready to send a PR.
45 |
46 | ### Notes on building with the Microsoft internal toolchain
47 |
48 | When we're building this project internally, we need to use an internally-maintained fork of the rust toolchain. This toolchain needs to be used for all production work at Microsoft so we can stay compliant with Secure Development Lifecycle (SDL) requirements.
49 |
50 | **If you're external to Microsoft, this next section doesn't apply to you**. You
51 | can use the standard Rust toolchain.
52 |
53 | First, install the internal `msrustup` toolchain to install the right version of
54 | all our Rust tools. You can get it from the https://aka.ms/msrustup-win. After
55 | that installs, then you'll probably also need to run the following:
56 |
57 | ```
58 | rustup default ms-stable
59 | ```
60 |
61 | That'll select the ms toolchain as the default. If you ever want to switch back, you can always just run
62 |
63 | ```
64 | rustup default stable-x86_64-pc-windows-msvc
65 | ```
66 |
67 | Additionally, we've got a separate fork of our `.cargo/config.toml` we need to use for internal builds. Notably, this includes `-Cehcont_guard` to enable EH Continuation Metadata. It also redirects cargo to use our own package feed for dependencies.
68 |
69 | You can manually build with that config with:
70 |
71 | ```
72 | cargo build --config .cargo\ms-toolchain-config.toml
73 | ```
74 |
75 | Note, if you run that on the public toolchain, you'll most definitely run into ``error: unknown codegen option: `ehcont_guard` `` when building.
76 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Microsoft Open Source Code of Conduct
2 |
3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
4 |
5 | Resources:
6 |
7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
10 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Sudo for Windows Contributor's Guide
2 |
3 | Below is our guidance for how to report issues, propose new features, and submit
4 | contributions via Pull Requests (PRs). Our philosophy is heavily based around
5 | understanding the problem and scenarios first, this is why we follow this
6 | pattern before work has started.
7 |
8 | 1. There is an issue
9 | 2. There has been a conversation
10 | 3. There is agreement on the problem, the fit for Sudo for Windows, and the
11 | solution to the problem (implementation)
12 |
13 | ## Filing an issue
14 |
15 | Please follow this simple rule to help us eliminate any unnecessary wasted
16 | effort & frustration, and ensure an efficient and effective use of everyone's
17 | time - yours, ours, and other community members':
18 |
19 | > 👉 If you have a question, think you've discovered an issue, would like to
20 | > propose a new feature, etc., then find/file an issue **BEFORE** starting work
21 | > to fix/implement it.
22 |
23 | When requesting new features / enhancements, understanding problem and scenario
24 | around it is extremely important. Having additional evidence, data, tweets, blog
25 | posts, research, ... anything is extremely helpful. This information provides
26 | context to the scenario that may otherwise be lost.
27 |
28 | * Don't know whether you're reporting an issue or requesting a feature? **File an issue**
29 | * Have a question that you don't see answered in docs, videos, etc.? **File an issue**
30 | * Want to know if we're planning on building a particular feature? **File an issue**
31 | * Got a great idea for a new feature? **File an issue**
32 | * Don't understand how to do something? **File an issue**
33 | * Found an existing issue that describes yours? **Great!** upvote and add
34 | additional commentary / info / repro-steps / etc.
35 |
36 | A quick search before filing an issue also could be helpful. It is likely
37 | someone else has found the problem you're seeing, and someone may be working on
38 | or have already contributed a fix!
39 |
40 | ### Reporting Security Issues
41 |
42 | **Please do not report security vulnerabilities through public GitHub issues.**
43 | Instead, please report them to the Microsoft Security Response Center (MSRC).
44 | See [SECURITY.md](./SECURITY.md) for more information.
45 |
46 | ### How to tell the Sudo team "this is an interesting thing to focus on"
47 |
48 | Upvote the original issue by clicking its [+😊] button and hitting 👍 (+1) icon
49 | or a different one. This way allows us to measure how impactful different issues
50 | are compared to others. The issue with comments like "+1", "me too", or similar
51 | is they actually make it harder to have a conversation and harder to quickly
52 | determine trending important requests.
53 |
54 | ### Localization issues
55 |
56 | Please file localization issues, so our internal localization team can identify
57 | and fix them. However we currently don't accept community Pull Requests fixing
58 | localization issues. Localization is handled by the internal Microsoft team
59 | only.
60 |
61 | ## Contributing code
62 |
63 | As you might imagine, shipping something inside of Windows is a complicated
64 | process--doubly so for a security component. There is a lot of validation and
65 | paperwork that we don't really want to subject the community to. We want you to
66 | be able to contribute easily and freely, and to let us deal with the paperwork.
67 | We'll do our best to make sure this process is as seamless as possible.
68 |
69 | To support the community in building new feature areas for Sudo for Windows,
70 | we're going to make extensive use of feature flags, to conditionally add new
71 | features to Sudo for Windows.
72 |
73 | When contributing to Sudo for Windows, we will treat "bugfixes" and "features"
74 | separately. Bug fixes can be merged into the codebase freely, so long as they
75 | don't majorly change existing behaviors. New features will need to have their
76 | code guarded by feature flag checks before we can accept them as contributions.
77 |
78 | As always, filing issues on the repo is the best way to have the team evaluate
79 | if the change you're proposing would be considered a "bug fix" or "feature"
80 | work. We will indicate which is which using the `Issue-Bug` and
81 | `Issue-Feature`/`Issue-Task` labels. These labels are intended to be informative,
82 | and may change throughout the lifecycle of a discussion.
83 |
84 | We'll be grouping sets of feature flags into different "branding"s throughout
85 | the project. These brandings are as follows:
86 | * **"Inbox"**: These are features that are included in the version of sudo that
87 | ships with Windows itself.
88 | * **"Stable"**: Features that ship in stable versions of sudo released here on
89 | GitHub and on WinGet.
90 | * **"Dev"**: The least stable features, which are only built in local development
91 | builds. These are for work-in-progress features, that aren't quite ready for
92 | public consumption
93 |
94 | All new features should be added under the "Dev" branding first. The core team
95 | will then be responsible for moving those features into the appropriate branding
96 | as we get internal signoffs. This will allow features to be worked on
97 | continually in the open, while we slowly roll them into the OS product. We
98 | unfortunately cannot provide timelines for when features will be able to move
99 | from Stable into Inbox. Historical data showing that a feature has a track
100 | record of being stable and secure is a great way for us to justify any
101 | particular feature's inclusion into the product.
102 |
103 | If you're ready to jump in, head on over to [Building.md](./Building.md) to get
104 | started.
105 |
106 | ## Repo Bot
107 |
108 | The team triages new issues several times a week. During triage, the team uses
109 | labels to categorize, manage, and drive the project workflow.
110 |
111 | We employ a bot engine to help us automate common processes within our workflow.
112 |
113 | We drive the bot by tagging issues with specific labels which cause the bot
114 | engine to close issues, merge branches, etc. This bot engine helps us keep the
115 | repo clean by automating the process of notifying appropriate parties if/when
116 | information/follow-up is needed, and closing stale issues/PRs after reminders
117 | have remained unanswered for several days.
118 |
119 | Therefore, if you do file issues, or create PRs, please keep an eye on your
120 | GitHub notifications. If you do not respond to requests for information, your
121 | issues/PRs may be closed automatically.
122 |
123 | ## Thank you
124 |
125 | Thank you in advance for your contribution!
126 |
127 | [`sudo.ps1`]: ./scripts/sudo.ps1
128 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [workspace]
2 | resolver = "2"
3 |
4 | members = [
5 | "sudo",
6 | "sudo_events",
7 | "win32resources",
8 | ]
9 |
10 | # This list of dependencies allows us to specify version numbers for dependency in a single place.
11 | # The dependencies in this list are _not_ automatically added to crates (Cargo.toml files).
12 | # Each individual Cargo.toml file must explicitly declare its dependencies. To use a dependency
13 | # from this list, specify "foo.workspace = true". For example:
14 | #
15 | # [dependencies]
16 | # log.workspace = true
17 | #
18 | # See: https://doc.rust-lang.org/cargo/reference/workspaces.html#the-dependencies-table
19 | #
20 | [workspace.dependencies]
21 | cc = "1.0"
22 | # We're disabling the default features for clap because we don't need the
23 | # "suggestions" feature. That provides really amazing suggestions for typos, but
24 | # it unfortunately does not seem to support localization.
25 | #
26 | # To use clap at all, you do need the std feature enabled, so enable that.
27 | #
28 | # See: https://docs.rs/clap/latest/clap/_features/index.html
29 | clap = { version = "4.4.7", default-features = false, features = ["std"] }
30 | embed-manifest = "1.4"
31 | which = "6.0"
32 | win_etw_provider = "0.1.8"
33 | win_etw_macros = "0.1.8"
34 | windows = "0.57"
35 | windows-registry = "0.1"
36 | winres = "0.1"
37 |
38 | # For more profile settings, and details on the ones below, see https://doc.rust-lang.org/cargo/reference/profiles.html#profile-settings
39 | [profile.release]
40 | # Enable full debug info for optimized builds.
41 | debug = "full"
42 | # Split debuginfo into its own file to reduce binary size.
43 | split-debuginfo = "packed"
44 | lto = true
45 | panic = "abort"
46 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) Microsoft Corporation. All rights reserved.
2 |
3 | MIT License
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/NOTICE.md:
--------------------------------------------------------------------------------
1 | # NOTICES AND INFORMATION
2 | Do Not Translate or Localize
3 |
4 | This software incorporates material from third parties. Microsoft makes certain
5 | open source code available at [http://3rdpartysource.microsoft.com](http://3rdpartysource.microsoft.com), or you may
6 | send a check or money order for US $5.00, including the product name, the open
7 | source component name, and version number, to:
8 |
9 | ```
10 | Source Code Compliance Team
11 | Microsoft Corporation
12 | One Microsoft Way
13 | Redmond, WA 98052
14 | USA
15 | ```
16 |
17 | Notwithstanding any other terms, you may reverse engineer this software to the
18 | extent required to debug changes to any libraries licensed under the GNU Lesser
19 | General Public License.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #  Sudo for Windows
2 |
3 | Welcome to the repository for [Sudo for Windows][sudo-for-windows] 🥪. Sudo
4 | for Windows allows users to run elevated commands directly from unelevated
5 | terminal windows.
6 |
7 | The "Inbox" version of sudo is available for Windows 11 builds 26045 and later. If you're on an Insiders
8 | build with sudo, you can enable it in the Windows Settings app, on the
9 | "Developer Features" page.
10 |
11 | Here you can report issues and file feature requests.
12 |
13 | ## Relationship to `sudo` on Unix/Linux
14 |
15 | Everything about permissions and the command line experience is
16 | different between Windows and Linux. This project is not a fork of the Unix/Linux
17 | `sudo` project, nor is it a port of that `sudo` project. Instead, Sudo for
18 | Windows is a Windows-specific implementation of the `sudo` concept.
19 |
20 | As the two are entirely different applications, you'll find that certain
21 | elements of the traditional `sudo` experience are not present in Sudo for Windows, and
22 | vice versa. Scripts and documentation that are written for `sudo` may not
23 | be able to be used directly with Sudo for Windows without some modification.
24 |
25 | ## Documentation
26 |
27 | All project documentation is located at
28 | [aka.ms/sudo-docs][sudo-docs]. If you would like to contribute to
29 | the documentation, please submit a pull request on the [Sudo for Windows
30 | Documentation repo][documentation-repo].
31 |
32 | ## Contributing
33 |
34 | Check out [CONTRIBUTING.md](https://github.com/microsoft/sudo/blob/main/CONTRIBUTING.md) for details on how to contribute to this project.
35 |
36 | ### `sudo.ps1`
37 |
38 | In the meantime, you can contribute to the [`sudo.ps1`] script. This script is
39 | meant to be a helper wrapper around `sudo.exe` that provides a more
40 | user-friendly experience for using sudo from PowerShell. This script is located
41 | in the `scripts/` directory.
42 |
43 | ## Communicating with the Team
44 |
45 | The easiest way to communicate with the team is via GitHub issues.
46 |
47 | Please file new issues, feature requests and suggestions, but **DO search for
48 | similar open/closed preexisting issues before creating a new issue.**
49 |
50 | If you would like to ask a question that you feel doesn't warrant an issue
51 | (yet), try a [discussion thread][discussions]. Those are especially helpful for question &
52 | answer threads. Otherwise, you can reach out to us via your social media
53 | platform of choice:
54 |
55 | * Mike Griese, Senior Developer: [@zadjii@mastodon.social](https://mastodon.social/@zadjii)
56 | * Jordi Adoumie, Product Manager: [@joadoumie](https://twitter.com/joadoumie)
57 | * Dustin Howett, Engineering Lead: [@dhowett@mas.to](https://mas.to/@DHowett)
58 | * Clint Rutkas, Lead Product Manager: [@crutkas](https://twitter.com/clintrutkas)
59 |
60 | ## Code of Conduct
61 |
62 | This project has adopted the [Microsoft Open Source Code of
63 | Conduct][conduct-code]. For more information see the [Code of Conduct
64 | FAQ][conduct-FAQ] or contact [opencode@microsoft.com][conduct-email] with any
65 | additional questions or comments.
66 |
67 | [conduct-code]: https://opensource.microsoft.com/codeofconduct/
68 | [conduct-FAQ]: https://opensource.microsoft.com/codeofconduct/faq/
69 | [conduct-email]: mailto:opencode@microsoft.com
70 | [`sudo.ps1`]: ./scripts/sudo.ps1
71 | [discussions]: https://github.com/microsoft/sudo/discussions
72 | [sudo-for-windows]: https://aka.ms/sudo
73 | [sudo-docs]: https://aka.ms/sudo-docs
74 | [documentation-repo]: https://github.com/MicrosoftDocs/windows-dev-docs/tree/docs/hub/sudo
75 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [many more](https://opensource.microsoft.com/).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [definition](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
40 |
41 |
42 |
--------------------------------------------------------------------------------
/SUPPORT.md:
--------------------------------------------------------------------------------
1 | # Support
2 |
3 | ## How to file issues and get help
4 |
5 | This project uses [GitHub issues][gh-issue] to [track bugs][gh-bug] and [feature
6 | requests][gh-feature]. Please search the existing issues before filing new
7 | issues to avoid duplicates. For new topics, file your bug or feature request as
8 | a new issue.
9 |
10 | For help and questions about using this project, please look at the [docs site
11 | for Sudo for Windows][docs] and our [Contributor's Guide][contributor] if you
12 | want to work on Sudo for Windows.
13 |
14 | ## Microsoft Support Policy
15 |
16 | Support for Sudo for Windows is limited to the resources listed above.
17 |
18 | [gh-issue]: https://github.com/microsoft/sudo/issues/new/choose
19 | [gh-bug]: https://github.com/microsoft/sudo/issues/new?assignees=&labels=Issue-Bug&template=bug_report.md&title=
20 | [gh-feature]: https://github.com/microsoft/sudo/issues/new?assignees=&labels=Issue-Feature&template=Feature_Request.md&title=
21 | [docs]: https://aka.ms/sudo-docs
22 | [contributor]: ./CONTRIBUTING.md
23 |
--------------------------------------------------------------------------------
/cpp/logging/EventViewerLogging.c:
--------------------------------------------------------------------------------
1 | #define NOMINMAX
2 | #define WIN32_LEAN_AND_MEAN
3 | #include
4 |
5 | #include
6 |
7 | #include "instrumentation.h" // Generated from manifest
8 |
--------------------------------------------------------------------------------
/cpp/logging/README.md:
--------------------------------------------------------------------------------
1 | ## Helpful info for Event Viewer logging
2 |
3 | This C++ project logs to the Windows Event Viewer. It's all wired up to be called from Rust just the same as our RPC code. If you want to test changes here:
4 |
5 | 1. Make sure to go change the `resourceFileName` and the `messageFileName` in
6 | `instrumentation.man` to point at where the files are in your build
7 | directory. (For me, that was
8 | `D:\dev\private\sudo\target\x86_64-pc-windows-msvc\debug\sudo.exe`). It needs
9 | to be the full path, so Event Viewer can find the exe (to load the resources
10 | from it to know how to format the packet of binary data written to it)
11 | - Make sure to change it back to `%systemroot%\System32\sudo.exe` before you push!
12 | 2. Make sure that Event Viewer is closed, and do
13 | ```bat
14 | wevtutil um cpp\logging\instrumentation.man
15 | ```
16 | to remove the old manifest from event viewer
17 | 3. Build the project
18 | 4. Do a
19 | ```bat
20 | wevtutil im cpp\logging\instrumentation.man
21 | ```
22 | to install the new manifest to event viewer
23 | 5. Open event viewer, and navigate to "Applications and Services Logs" ->
24 | "Microsoft" -> "Windows" -> "Sudo" -> "Admin"
25 | - alternatively:
26 | ```bat
27 | wevtutil qe Microsoft-Windows-Sudo/Admin /c:3 /rd:true /f:text
28 | ```
29 |
--------------------------------------------------------------------------------
/cpp/logging/instrumentation.man:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | %1
44 | %2
45 | %3
46 | %4
47 | %5
48 | %6
49 | %7
50 | %8
51 | %9
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
66 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/cpp/rpc/README.md:
--------------------------------------------------------------------------------
1 | # Sudo RPC library
2 |
3 | To do local RPC, we need to use midl to generate function bindings for our RPC
4 | interface, which is defined in `sudo_rpc.idl`. midl expects implementations and
5 | callbacks via C functions which we can do in Rust, but there's one problem:
6 | Error handling on the client side occurs with structed exceptions (SEH).
7 | Those cannot be easily replicated in pure Rust and so the client side calls
8 | are all wrapped in C functions.
9 |
10 | Changes here go as follows:
11 | * Change the interface in `sudo_rpc.idl`
12 | * Write a client-side wrapper in `RpcClient.c` in the style of the other ones
13 | * Implement a client-side wrapper Rust in `rpc_bindings_client.rs`
14 | * Implement the server-side part in `rpc_bindings_server.rs`
15 |
16 | Be careful about the function definitions. At the moment, there are no checks
17 | in place that ensure that the Rust code matches the C code or the .idl file.
18 |
--------------------------------------------------------------------------------
/cpp/rpc/RpcClient.c:
--------------------------------------------------------------------------------
1 | #define WIN32_LEAN_AND_MEAN
2 | #include
3 |
4 | #include
5 | #include
6 |
7 | // Our generated header file
8 | #include "sudo_rpc.h"
9 |
10 | // Rust can't (easily) handle SEH exceptions, which the RPC however unfortunately uses.
11 | // And so this wrapper C implementation exists.
12 |
13 | // From :
14 | // Some RPC exceptions are already HRESULTs. Others are in the regular Win32
15 | // error space. If the incoming exception code isn't an HRESULT, wrap it.
16 | inline HRESULT map_rpc_status(DWORD code)
17 | {
18 | return IS_ERROR(code) ? code : HRESULT_FROM_WIN32(code);
19 | }
20 |
21 | HRESULT seh_wrapper_client_DoElevationRequest(
22 | RPC_IF_HANDLE binding,
23 | HANDLE parent_handle,
24 | const HANDLE* pipe_handles,
25 | const HANDLE* file_handles,
26 | DWORD sudo_mode,
27 | UTF8_STRING application,
28 | UTF8_STRING args,
29 | UTF8_STRING target_dir,
30 | UTF8_STRING env_vars,
31 | GUID eventId,
32 | HANDLE* child)
33 | {
34 | RpcTryExcept
35 | {
36 | return client_DoElevationRequest(
37 | binding,
38 | parent_handle,
39 | pipe_handles,
40 | file_handles,
41 | sudo_mode,
42 | application,
43 | args,
44 | target_dir,
45 | env_vars,
46 | eventId,
47 | child);
48 | }
49 | RpcExcept(RpcExceptionFilter(RpcExceptionCode()))
50 | {
51 | return map_rpc_status(RpcExceptionCode());
52 | }
53 | RpcEndExcept;
54 | }
55 |
56 | HRESULT seh_wrapper_client_Shutdown(RPC_IF_HANDLE binding)
57 | {
58 | RpcTryExcept
59 | {
60 | client_Shutdown(binding);
61 | return S_OK;
62 | }
63 | RpcExcept(RpcExceptionFilter(RpcExceptionCode()))
64 | {
65 | return map_rpc_status(RpcExceptionCode());
66 | }
67 | RpcEndExcept;
68 | }
69 |
70 | /******************************************************/
71 | /* MIDL allocate and free */
72 | /******************************************************/
73 |
74 | void __RPC_FAR* __RPC_USER midl_user_allocate(size_t len)
75 | {
76 | return (malloc(len));
77 | }
78 |
79 | void __RPC_USER midl_user_free(void __RPC_FAR* ptr)
80 | {
81 | free(ptr);
82 | }
83 |
--------------------------------------------------------------------------------
/cpp/rpc/sudo_rpc.acf:
--------------------------------------------------------------------------------
1 | [implicit_handle(handle_t sudo_rpc_IfHandle)]
2 | interface sudo_rpc
3 | {
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/cpp/rpc/sudo_rpc.idl:
--------------------------------------------------------------------------------
1 | // This is where GUID is defined:
2 | import "wtypesbase.idl";
3 |
4 | typedef struct tagUTF8_STRING {
5 | DWORD length;
6 | [size_is(length)] const unsigned char *data;
7 | } UTF8_STRING;
8 |
9 | [
10 | uuid (f691b703-f681-47dc-afcd-034b2faab911), // You must change this when you change the interface
11 | version(1.0),
12 | ]
13 | interface sudo_rpc
14 | {
15 | HRESULT DoElevationRequest(
16 | [in] handle_t binding,
17 | [in, system_handle(sh_process)] HANDLE parent_handle,
18 | [in, system_handle(sh_pipe), unique, size_is(3)] const HANDLE* pipe_handles, // in, out, err
19 | [in, system_handle(sh_file), unique, size_is(3)] const HANDLE* file_handles, // in, out, err
20 | [in] DWORD sudo_mode,
21 | [in] UTF8_STRING application,
22 | [in] UTF8_STRING args, // a null-delimited list
23 | [in] UTF8_STRING target_dir,
24 | [in] UTF8_STRING env_vars, // a null-delimited list
25 | [in] GUID eventId,
26 | [out, system_handle(sh_process)] HANDLE* child
27 | );
28 |
29 | void Shutdown([in] handle_t h1);
30 | }
31 |
--------------------------------------------------------------------------------
/docs/generate.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | @rem calculate the next version number based on whatever the last draft-xyz.docx file is
4 | @rem this is a bit of a hack, but it works
5 |
6 | @rem get the last draft file
7 | for /f "delims=" %%a in ('dir /b /on draft-*.docx') do set lastdraft=%%a
8 |
9 | @rem if we didn't find an existing one, start with 000
10 | if "%lastdraft%"=="" set lastdraft=draft-000.docx
11 |
12 | @rem get the version number from the last draft file
13 | for /f "tokens=2 delims=-." %%a in ("%lastdraft%") do set /a version=%%a+1
14 |
15 | echo Generating draft-%version%.docx...
16 |
17 | @rem create the new draft file
18 | @rem
19 | @rem mermaid-filter.cmd is from github.com/raghur/mermaid-filter. That's deeply
20 | @rem out of date, so some of the newer features are missing. You can manually
21 | @rem patch the mermaid.min.js if you want though.
22 | pandoc -s -F mermaid-filter.cmd --from=markdown+yaml_metadata_block --to=docx .\draft.md -o .\draft-%version%.docx
23 |
24 | @rem delete mermaid-filter.err, if it's empty
25 |
26 | if exist mermaid-filter.err (
27 | for %%a in (mermaid-filter.err) do if %%~za==0 del mermaid-filter.err
28 | )
29 |
--------------------------------------------------------------------------------
/docs/obsidian-callouts.lua:
--------------------------------------------------------------------------------
1 | local stringify = (require "pandoc.utils").stringify
2 |
3 | function BlockQuote (el)
4 | start = el.content[1]
5 | if (start.t == "Para" and start.content[1].t == "Str" and
6 | start.content[1].text:match("^%[!%w+%][-+]?$")) then
7 | _, _, ctype = start.content[1].text:find("%[!(%w+)%]")
8 | el.content:remove(1)
9 | start.content:remove(1)
10 | div = pandoc.Div(el.content, {class = "callout"})
11 | div.attributes["data-callout"] = ctype:lower()
12 | div.attributes["title"] = stringify(start.content):gsub("^ ", "")
13 | return div
14 | else
15 | return el
16 | end
17 | end
--------------------------------------------------------------------------------
/docs/settings-app-toggle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/docs/settings-app-toggle.png
--------------------------------------------------------------------------------
/docs/sudo-conhost.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/docs/sudo-conhost.png
--------------------------------------------------------------------------------
/docs/sudo-terminal-multi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/docs/sudo-terminal-multi.png
--------------------------------------------------------------------------------
/docs/sudo-terminal-redirected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/docs/sudo-terminal-redirected.png
--------------------------------------------------------------------------------
/docs/sudo-terminal-service.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/docs/sudo-terminal-service.png
--------------------------------------------------------------------------------
/docs/sudo-terminal-single.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/docs/sudo-terminal-single.png
--------------------------------------------------------------------------------
/docs/sudo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/docs/sudo.png
--------------------------------------------------------------------------------
/docs/versions.md:
--------------------------------------------------------------------------------
1 | # Sudo for Windows - Versions
2 |
3 | There are a few different versions of Sudo for Windows - this doc aims to
4 | outline the differences between them. Each includes different sets of code, and
5 | releases in different cadences.
6 |
7 | * **"Inbox"**: This is the version of Sudo that ships with Windows itself. This
8 | is the most stable version, and might only include a subset of the features in
9 | the source code. This is delivered with the OS, via servicing upgrades.
10 | - Build this version with `cargo build --no-default-features --features Inbox`
11 | * **"Stable"**: The stable version of Sudo for Windows which ships out of this
12 | repo. This can be installed side-by-side with the inbox version.
13 | - Build this version with `cargo build --no-default-features --features Stable`
14 | * **"Dev"**: This is a local-only build of sudo. This has all the bits of code
15 | turned on, for the most up-to-date version of the code.
16 | - Build this version with `cargo build`
17 |
18 | Dev builds are the default for local compilation, to make the development inner loop the
19 | easiest.
20 |
21 | For more info, see "[Contributing code](../CONTRIBUTING.md#contributing-code)" in
22 | the contributors guide.
23 |
--------------------------------------------------------------------------------
/enable_sudo.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | net session >nul 2>&1
4 | if %errorLevel% == 0 (
5 | goto :do_it
6 | )
7 |
8 | echo You need to be admin to enable sudo!
9 | goto :exit
10 |
11 | :do_it
12 | echo Enabling sudo...
13 |
14 | set key=HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Sudo
15 | set value=Enabled
16 | set data=3
17 | reg add "%key%" /v "%value%" /t REG_DWORD /d %data% /f
18 |
19 | :exit
20 |
--------------------------------------------------------------------------------
/img/Windows/AppList.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.scale-100.png
--------------------------------------------------------------------------------
/img/Windows/AppList.scale-100_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.scale-100_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/AppList.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.scale-125.png
--------------------------------------------------------------------------------
/img/Windows/AppList.scale-125_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.scale-125_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/AppList.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.scale-150.png
--------------------------------------------------------------------------------
/img/Windows/AppList.scale-150_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.scale-150_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/AppList.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.scale-200.png
--------------------------------------------------------------------------------
/img/Windows/AppList.scale-200_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.scale-200_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/AppList.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.scale-400.png
--------------------------------------------------------------------------------
/img/Windows/AppList.scale-400_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.scale-400_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-16.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-16_altform-lightunplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-16_altform-lightunplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-16_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-16_altform-unplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-20.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-20_altform-lightunplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-20_altform-lightunplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-20_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-20_altform-unplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-24.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-24_altform-lightunplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-24_altform-lightunplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-24_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-24_altform-unplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-256.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-256_altform-lightunplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-256_altform-lightunplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-256_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-256_altform-unplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-30.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-30.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-30_altform-lightunplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-30_altform-lightunplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-30_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-30_altform-unplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-32.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-32_altform-lightunplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-32_altform-lightunplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-32_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-32_altform-unplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-36.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-36_altform-lightunplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-36_altform-lightunplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-36_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-36_altform-unplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-40.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-40_altform-lightunplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-40_altform-lightunplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-40_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-40_altform-unplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-48.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-48_altform-lightunplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-48_altform-lightunplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-48_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-48_altform-unplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-56.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-56.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-56_altform-lightunplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-56_altform-lightunplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-56_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-56_altform-unplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-60.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-60_altform-lightunplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-60_altform-lightunplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-60_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-60_altform-unplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-64.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-64_altform-lightunplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-64_altform-lightunplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-64_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-64_altform-unplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-72.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-72_altform-lightunplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-72_altform-lightunplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-72_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-72_altform-unplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-80.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-80.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-80_altform-lightunplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-80_altform-lightunplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-80_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-80_altform-unplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-96.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-96_altform-lightunplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-96_altform-lightunplated.png
--------------------------------------------------------------------------------
/img/Windows/AppList.targetsize-96_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/AppList.targetsize-96_altform-unplated.png
--------------------------------------------------------------------------------
/img/Windows/BadgeLogo.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/BadgeLogo.scale-100.png
--------------------------------------------------------------------------------
/img/Windows/BadgeLogo.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/BadgeLogo.scale-125.png
--------------------------------------------------------------------------------
/img/Windows/BadgeLogo.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/BadgeLogo.scale-150.png
--------------------------------------------------------------------------------
/img/Windows/BadgeLogo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/BadgeLogo.scale-200.png
--------------------------------------------------------------------------------
/img/Windows/BadgeLogo.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/BadgeLogo.scale-400.png
--------------------------------------------------------------------------------
/img/Windows/LargeTile.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/LargeTile.scale-100.png
--------------------------------------------------------------------------------
/img/Windows/LargeTile.scale-100_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/LargeTile.scale-100_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/LargeTile.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/LargeTile.scale-125.png
--------------------------------------------------------------------------------
/img/Windows/LargeTile.scale-125_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/LargeTile.scale-125_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/LargeTile.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/LargeTile.scale-150.png
--------------------------------------------------------------------------------
/img/Windows/LargeTile.scale-150_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/LargeTile.scale-150_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/LargeTile.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/LargeTile.scale-200.png
--------------------------------------------------------------------------------
/img/Windows/LargeTile.scale-200_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/LargeTile.scale-200_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/LargeTile.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/LargeTile.scale-400.png
--------------------------------------------------------------------------------
/img/Windows/LargeTile.scale-400_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/LargeTile.scale-400_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/MedTile.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/MedTile.scale-100.png
--------------------------------------------------------------------------------
/img/Windows/MedTile.scale-100_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/MedTile.scale-100_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/MedTile.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/MedTile.scale-125.png
--------------------------------------------------------------------------------
/img/Windows/MedTile.scale-125_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/MedTile.scale-125_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/MedTile.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/MedTile.scale-150.png
--------------------------------------------------------------------------------
/img/Windows/MedTile.scale-150_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/MedTile.scale-150_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/MedTile.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/MedTile.scale-200.png
--------------------------------------------------------------------------------
/img/Windows/MedTile.scale-200_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/MedTile.scale-200_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/MedTile.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/MedTile.scale-400.png
--------------------------------------------------------------------------------
/img/Windows/MedTile.scale-400_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/MedTile.scale-400_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/SmallTile.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SmallTile.scale-100.png
--------------------------------------------------------------------------------
/img/Windows/SmallTile.scale-100_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SmallTile.scale-100_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/SmallTile.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SmallTile.scale-125.png
--------------------------------------------------------------------------------
/img/Windows/SmallTile.scale-125_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SmallTile.scale-125_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/SmallTile.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SmallTile.scale-150.png
--------------------------------------------------------------------------------
/img/Windows/SmallTile.scale-150_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SmallTile.scale-150_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/SmallTile.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SmallTile.scale-200.png
--------------------------------------------------------------------------------
/img/Windows/SmallTile.scale-200_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SmallTile.scale-200_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/SmallTile.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SmallTile.scale-400.png
--------------------------------------------------------------------------------
/img/Windows/SmallTile.scale-400_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SmallTile.scale-400_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/SplashScreen.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SplashScreen.scale-100.png
--------------------------------------------------------------------------------
/img/Windows/SplashScreen.scale-100_altform-colorful_theme-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SplashScreen.scale-100_altform-colorful_theme-dark.png
--------------------------------------------------------------------------------
/img/Windows/SplashScreen.scale-100_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SplashScreen.scale-100_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/SplashScreen.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SplashScreen.scale-125.png
--------------------------------------------------------------------------------
/img/Windows/SplashScreen.scale-125_altform-colorful_theme-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SplashScreen.scale-125_altform-colorful_theme-dark.png
--------------------------------------------------------------------------------
/img/Windows/SplashScreen.scale-125_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SplashScreen.scale-125_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/SplashScreen.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SplashScreen.scale-150.png
--------------------------------------------------------------------------------
/img/Windows/SplashScreen.scale-150_altform-colorful_theme-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SplashScreen.scale-150_altform-colorful_theme-dark.png
--------------------------------------------------------------------------------
/img/Windows/SplashScreen.scale-150_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SplashScreen.scale-150_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/SplashScreen.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SplashScreen.scale-200.png
--------------------------------------------------------------------------------
/img/Windows/SplashScreen.scale-200_altform-colorful_theme-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SplashScreen.scale-200_altform-colorful_theme-dark.png
--------------------------------------------------------------------------------
/img/Windows/SplashScreen.scale-200_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SplashScreen.scale-200_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/SplashScreen.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SplashScreen.scale-400.png
--------------------------------------------------------------------------------
/img/Windows/SplashScreen.scale-400_altform-colorful_theme-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SplashScreen.scale-400_altform-colorful_theme-dark.png
--------------------------------------------------------------------------------
/img/Windows/SplashScreen.scale-400_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/SplashScreen.scale-400_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/StoreDisplay-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/StoreDisplay-150.png
--------------------------------------------------------------------------------
/img/Windows/StoreDisplay-300.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/StoreDisplay-300.png
--------------------------------------------------------------------------------
/img/Windows/StoreDisplay-71.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/StoreDisplay-71.png
--------------------------------------------------------------------------------
/img/Windows/StoreLogo.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/StoreLogo.scale-100.png
--------------------------------------------------------------------------------
/img/Windows/StoreLogo.scale-100_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/StoreLogo.scale-100_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/StoreLogo.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/StoreLogo.scale-125.png
--------------------------------------------------------------------------------
/img/Windows/StoreLogo.scale-125_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/StoreLogo.scale-125_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/StoreLogo.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/StoreLogo.scale-150.png
--------------------------------------------------------------------------------
/img/Windows/StoreLogo.scale-150_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/StoreLogo.scale-150_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/StoreLogo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/StoreLogo.scale-200.png
--------------------------------------------------------------------------------
/img/Windows/StoreLogo.scale-200_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/StoreLogo.scale-200_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/StoreLogo.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/StoreLogo.scale-400.png
--------------------------------------------------------------------------------
/img/Windows/StoreLogo.scale-400_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/StoreLogo.scale-400_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/WideTile.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/WideTile.scale-100.png
--------------------------------------------------------------------------------
/img/Windows/WideTile.scale-100_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/WideTile.scale-100_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/WideTile.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/WideTile.scale-125.png
--------------------------------------------------------------------------------
/img/Windows/WideTile.scale-125_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/WideTile.scale-125_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/WideTile.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/WideTile.scale-150.png
--------------------------------------------------------------------------------
/img/Windows/WideTile.scale-150_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/WideTile.scale-150_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/WideTile.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/WideTile.scale-200.png
--------------------------------------------------------------------------------
/img/Windows/WideTile.scale-200_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/WideTile.scale-200_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/Windows/WideTile.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/WideTile.scale-400.png
--------------------------------------------------------------------------------
/img/Windows/WideTile.scale-400_altform-colorful_theme-light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/Windows/WideTile.scale-400_altform-colorful_theme-light.png
--------------------------------------------------------------------------------
/img/ico/Sudo.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/ico/Sudo.ico
--------------------------------------------------------------------------------
/img/ico/_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/ico/_16.png
--------------------------------------------------------------------------------
/img/ico/_20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/ico/_20.png
--------------------------------------------------------------------------------
/img/ico/_24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/ico/_24.png
--------------------------------------------------------------------------------
/img/ico/_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/ico/_256.png
--------------------------------------------------------------------------------
/img/ico/_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/ico/_32.png
--------------------------------------------------------------------------------
/img/ico/_40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/ico/_40.png
--------------------------------------------------------------------------------
/img/ico/_48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/ico/_48.png
--------------------------------------------------------------------------------
/img/ico/_64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/sudo/9c53e97eb4fc58c9e135045946881123e0851528/img/ico/_64.png
--------------------------------------------------------------------------------
/img/svg/ic_fluent_Sudo.svg:
--------------------------------------------------------------------------------
1 |
71 |
--------------------------------------------------------------------------------
/owners.txt:
--------------------------------------------------------------------------------
1 | ; This owners file addition was requested by migrie@microsoft.com
2 | ; This owners.txt file was initially populated by Easy Start. Every code
3 | ; change inside of an Ownership Enforcer enabled branch (such as master) must be
4 | ; approved by at least one expert listed in an applicable owners.txt file. This
5 | ; root owners.txt file is applicable to every change. Targeted experts can be
6 | ; defined by placing an owners.txt file inside any subdirectory. More information
7 | ; about Ownership Enforcer can be found at https://aka.ms/ownershipenforcer.
8 | migrie
9 | duhowett
--------------------------------------------------------------------------------
/scripts/sudo.ps1:
--------------------------------------------------------------------------------
1 | # Copyright (c) Microsoft Corporation.
2 | # Licensed under the MIT License.
3 |
4 | # open question - Should -NoProfile be used when invoking PowerShell
5 | BEGIN {
6 | if ($__SUDO_TEST -ne $true) {
7 | $SUDOEXE = "sudo.exe"
8 | }
9 | else {
10 | if ($null -eq $SUDOEXE) {
11 | throw "variable SUDOEXE has not been set for testing"
12 | }
13 | }
14 |
15 | if ([Environment]::OSVersion.Platform -ne "Win32NT") {
16 | throw "This script works only on Microsoft Windows"
17 | }
18 |
19 | if ($null -eq (Get-Command -Type Application -Name "$SUDOEXE" -ErrorAction Ignore)) {
20 | throw "'$SUDOEXE' cannot be found."
21 | }
22 |
23 | $psProcess = Get-Process -id $PID
24 | if (($null -eq $psProcess) -or ($psProcess.Count -ne 1)) {
25 | throw "Cannot retrieve process for '$PID'"
26 | }
27 |
28 | $thisPowerShell = $psProcess.MainModule.FileName
29 | if ($null -eq $thisPowerShell) {
30 | throw "Cannot determine path to '$psProcess'"
31 | }
32 |
33 | function convertToBase64EncodedString([string]$cmdLine) {
34 | $bytes = [System.Text.Encoding]::Unicode.GetBytes($cmdLine)
35 | [Convert]::ToBase64String($bytes)
36 | }
37 |
38 | $MI = $MyInvocation
39 | }
40 |
41 | END {
42 | $cmdArguments = $args
43 |
44 | # short-circuit if the user provided a scriptblock, then we will use it and ignore any other arguments
45 | if ($cmdArguments.Count -eq 1 -and $cmdArguments[0] -is [scriptblock]) {
46 | $scriptBlock = $cmdArguments[0]
47 | $encodedCommand = convertToBase64EncodedString -cmdLine ($scriptBlock.ToString())
48 | if (($psversiontable.psversion.major -eq 7) -and ($__SUDO_DEBUG -eq $true)) {
49 | Trace-Command -PSHOST -name param* -Expression { & $SUDOEXE "$thisPowerShell" -e $encodedCommand }
50 | }
51 | else {
52 | & $SUDOEXE "$thisPowerShell" -e $encodedCommand
53 | }
54 | return
55 | }
56 |
57 | $cmdLine = $MI.Line
58 | $sudoOffset = $cmdLine.IndexOf($MI.InvocationName)
59 | $cmdLineWithoutScript = $cmdLine.SubString($sudoOffset + 5)
60 | $cmdLineAst = [System.Management.Automation.Language.Parser]::ParseInput($cmdLineWithoutScript, [ref]$null, [ref]$null)
61 | $commandAst = $cmdLineAst.Find({$args[0] -is [System.Management.Automation.Language.CommandAst]}, $false)
62 | $commandName = $commandAst.GetCommandName()
63 | $isApplication = Get-Command -Type Application -Name $commandName -ErrorAction Ignore | Select-Object -First 1
64 | $isCmdletOrScript = Get-Command -Type Cmdlet,ExternalScript -Name $commandName -ErrorAction Ignore | Select-Object -First 1
65 |
66 | # if the command is a native command, just invoke it
67 | if ($null -ne $isApplication) {
68 | if (($psversiontable.psversion.major -eq 7) -and ($__SUDO_DEBUG -eq $true)) {
69 | trace-command -PSHOST -name param* -Expression { & $SUDOEXE $cmdArguments }
70 | }
71 | else {
72 | & $SUDOEXE $cmdArguments
73 | }
74 | }
75 | elseif ($null -ne $isCmdletOrScript) {
76 | $encodedCommand = convertToBase64EncodedString($cmdLineWithoutScript)
77 | if (($psversiontable.psversion.major -eq 7) -and ($__SUDO_DEBUG -eq $true)) {
78 | trace-command -PSHOST -name param* -Expression { & $SUDOEXE -nologo -e $encodedCommand }
79 | }
80 | else {
81 | & $SUDOEXE $thisPowerShell -nologo -e $encodedCommand
82 | }
83 | }
84 | else {
85 | throw "Cannot find '$commandName'"
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/sudo/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "sudo"
3 | version = "1.0.1"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | build = "build.rs"
9 |
10 | [[bin]]
11 | test = true
12 | name = "sudo"
13 |
14 | [build-dependencies]
15 | winres.workspace = true
16 | cc.workspace = true
17 | embed-manifest.workspace = true
18 | which = { workspace = true }
19 |
20 | [dependencies]
21 |
22 | clap = { workspace = true, default-features = false, features = ["color", "help", "usage", "error-context"] }
23 | which = { workspace = true }
24 | windows-registry = { workspace = true }
25 |
26 | sudo_events = { path = "../sudo_events" }
27 | win32resources = { path = "../win32resources" }
28 |
29 | [dependencies.windows]
30 | workspace = true
31 | features = [
32 | "Wdk_Foundation",
33 | "Wdk_System_Threading",
34 | "Win32_Foundation",
35 | "Win32_Globalization",
36 | "Win32_Security",
37 | "Win32_Security_Authorization",
38 | "Win32_Storage_FileSystem",
39 | "Win32_System_Console",
40 | "Win32_System_Diagnostics_Debug",
41 | "Win32_System_Diagnostics_Etw",
42 | "Win32_System_Environment",
43 | "Win32_System_Kernel",
44 | "Win32_System_Memory",
45 | "Win32_System_Registry",
46 | "Win32_System_Rpc",
47 | "Win32_System_SystemInformation",
48 | "Win32_System_SystemServices",
49 | "Win32_System_Threading",
50 | "Win32_System_WindowsProgramming",
51 | "Win32_UI_Shell",
52 | "Win32_UI_WindowsAndMessaging",
53 | ]
54 |
55 | [features]
56 | # We attempt to use feature flags in a similar way to how the rest of the
57 | # Windows codebase does. We've got a set of "brandings", each which contain a
58 | # set of feature flags. Each branding is a superset of the previous branding,
59 | # and is progressively "less stable" that the previous.
60 | #
61 | # The idea is that we can build with a specific branding, and get all the
62 | # features that are enabled for that branding, plus all the "more stable" ones.
63 | #
64 | # We default to "Dev" branding, which has all the code turned on. Call `cargo
65 | # build --no-default-features --features Inbox` to just get the inbox build (for
66 | # example).
67 |
68 | ############################################
69 | # Feature flags
70 | Feature_test_flag = [] # This is a test feature flag, to demo how they can be used.
71 |
72 | ############################################
73 | # Branding
74 | # Put each individual feature flag into ONE of the following brandings
75 | Inbox = []
76 | Stable = ["Inbox"]
77 | Dev = ["Stable", "Feature_test_flag"]
78 |
79 | # by default, build everything. This is a little different than you'd typically
80 | # expect for a rust crate, but since we're not actually expecting anyone to be
81 | # ingesting us as a crate, it's fine.
82 | default = ["Dev"]
83 |
84 |
--------------------------------------------------------------------------------
/sudo/Resources/en-US/Sudo.resw:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Sudo for Windows
122 | {Locked=qps-ploc,qps-ploca,qps-plocm}
123 |
124 |
125 | Sudo for Windows.
126 | Can be used to run a command as admin. When run, will prompt for confirmation with a User Accounts Control dialog. Currently only supports running commands as the admin user who confirms the dialog.
127 |
128 | If used to run a console application, sudo will return when the target process exits.
129 | If used to run a graphical application (for example, notepad.exe), sudo will return immediately.
130 |
131 | In New Window mode, sudo will launch applications from the Windows directory in C:\\Windows\\System32. You can use the --chdir option to change the working directory before running the command.
132 |
133 | If a mode is omitted, sudo will use the mode set in the system settings. If a mode is specified with one of --new-window, --disable-input, or --inline, sudo will exit with an error if that mode is not currently allowed by the system settings.
134 |
135 | {Locked="sudo","notepad.exe","C:\\Windows\\System32","--chdir"}
136 |
137 |
138 | Sudo is disabled on this machine. To enable it, go to the \x1b]8;;ms-settings:developers\x1b\\Developer Settings page\x1b]8;;\x1b\\ in the Settings app
139 | {Locked="\x1b]8;;ms-settings:developers\x1b\\","\x1b]8;;\x1b\\"}
140 |
141 |
142 | Print help (see less with '-h')
143 | {Locked="-h"}
144 |
145 |
146 | Print help (see more with '--help')
147 | {Locked="--help"}
148 |
149 |
150 | Print version
151 |
152 |
153 | The elevate subcommand is for internal use only
154 | {Locked="elevate"}
155 |
156 |
157 | Parent process ID
158 |
159 |
160 | Command-line to run
161 |
162 |
163 | Get current configuration information of sudo
164 |
165 |
166 | Run a command as admin
167 |
168 |
169 | Pass the current environment variables to the command
170 |
171 |
172 | Use a new window for the command
173 |
174 |
175 | Run in the current terminal, with input to the target application disabled
176 |
177 |
178 | Run in the current terminal
179 | Description of a command-line flag that will cause sudo to run the target application in the current console window.
180 |
181 |
182 | Command-line to run
183 |
184 |
185 | Sudo is disabled by your organization's policy.
186 |
187 |
188 | Sudo is disabled on this machine.
189 |
190 |
191 | Invalid mode:
192 | This string will be followed by a string the user entered (which was and invalid value)
193 |
194 |
195 | Error setting mode:
196 | This string will be followed by an error message
197 |
198 |
199 | Unknown error:
200 | This string will be followed by an error message
201 |
202 |
203 | Sudo is currently in Force New Window mode on this machine
204 |
205 |
206 | Sudo is currently in Disable Input mode on this machine
207 | Message printed to the user informing them of the current sudo mode. In this case, the mode is the "Disable Input" mode.
208 |
209 |
210 | Sudo is currently in Inline mode on this machine
211 |
212 |
213 | You must run this command as an administrator.
214 |
215 |
216 | You cannot set a mode higher than Force New Window mode on this machine
217 | Error message printed when the user attempts to set sudo into a mode higher than the mode currently allowed by policy. In this case, the currently allowed mode is the "Force New Window" mode.
218 |
219 |
220 | You cannot set a mode higher than Disable Input mode on this machine
221 | Error message printed when the user attempts to set sudo into a mode higher than the mode currently allowed by policy. In this case, the currently allowed mode is the "Disable Input" mode.
222 |
223 |
224 | You cannot set a mode higher than Inline mode on this machine
225 | Error message printed when the user attempts to set sudo into a mode higher than the mode currently allowed by policy. In this case, the currently allowed mode is the "Inline" mode.
226 |
227 |
228 | Sudo mode set to Force New Window mode
229 |
230 |
231 | Sudo mode set to DisableInput mode
232 |
233 |
234 | Sudo mode set to Inline mode
235 |
236 |
237 | Command not found
238 |
239 |
240 | Operation was cancelled by the user
241 |
242 |
243 | Launched {0} in a new window.
244 | {0} will be replaced by the name of a command-line executable
245 |
246 |
247 | Change the working directory before running the command
248 |
249 |
250 | You cannot run in a mode higher than Force New Window mode on this machine
251 | Error message printed when the user requested a mode higher than the currently allowed mode. In this case, the currently allowed mode is the "Force New Window" mode.
252 |
253 |
254 | You cannot run in a mode higher than Disable Input mode on this machine
255 | Error message printed when the user requested a mode higher than the currently allowed mode. In this case, the currently allowed mode is the "Disable Input" mode.
256 |
257 |
258 | You cannot run in a mode higher than Inline mode on this machine
259 | Error message printed when the user requested a mode higher than the currently allowed mode. In this case, the currently allowed mode is the "Inline" mode.
260 |
261 |
262 | You are not allowed to preserve environment variables
263 | Error message printed when the user tries to preserve environment variables, but is not allowed to
264 |
265 |
266 | You are not allowed to run sudo
267 | Error message printed when the user is not allowed to run sudo because they aren't an administrator
268 |
269 |
270 | set USERPROFILE variable to target user's USERPROFILE
271 | {Locked="USERPROFILE"} Help text for a commandline arg that sets the USERPROFILE variable
272 |
273 |
274 |
--------------------------------------------------------------------------------
/sudo/build.rs:
--------------------------------------------------------------------------------
1 | use embed_manifest::embed_manifest_file;
2 | use std::path::PathBuf;
3 | use std::process::Command;
4 | use {
5 | std::{env, io},
6 | winres::WindowsResource,
7 | };
8 |
9 | fn get_sdk_path() -> Option {
10 | let mut sdk_path: Option = None;
11 | let target = env::var("TARGET").unwrap();
12 |
13 | // For whatever reason, find_tool doesn't work directly on `midl.exe`. It
14 | // DOES work however, on `link.exe`, and will hand us back a PATH that has
15 | // the path to the appropriate midl.exe in it.
16 | let link_exe = cc::windows_registry::find_tool(target.as_str(), "link.exe")
17 | .expect("Failed to find link.exe");
18 | link_exe.env().iter().for_each(|(k, v)| {
19 | if k == "PATH" {
20 | let elements = (v.to_str().expect("path exploded"))
21 | .split(';')
22 | .collect::>();
23 | // iterate over the elements to find one that starts with
24 | // "C:\Program Files (x86)\Windows Kits\10\bin\10.0.*"
25 | for element in elements {
26 | if element.starts_with("C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.") {
27 | sdk_path = Some(element.to_string());
28 | }
29 | }
30 | }
31 | });
32 | sdk_path
33 | }
34 |
35 | fn get_sdk_tool(sdk_path: &Option, tool_name: &str) -> String {
36 | // seems like, in a VS tools prompt, midl.exe is in the path so the above
37 | // doesn't include the path. kinda weird but okay?
38 | let tool_path = match sdk_path {
39 | Some(s) => PathBuf::from(s)
40 | .join(tool_name)
41 | .to_str()
42 | .unwrap()
43 | .to_owned(),
44 | None => {
45 | // This is the case that happens when you run the build from a VS
46 | // tools prompt. In this case, the tool is already in the path, so
47 | // we can just get the absolute path to the exe using the windows
48 | // path search.
49 |
50 | let tool_path = which::which(tool_name).expect("Failed to find tool in path");
51 | tool_path.to_str().unwrap().to_owned()
52 | }
53 | };
54 | tool_path
55 | }
56 |
57 | fn build_rpc() {
58 | // Build our RPC library
59 |
60 | let sdk_path: Option = get_sdk_path();
61 | let midl_path = get_sdk_tool(&sdk_path, "midl.exe");
62 |
63 | // Now, we need to get the path to the shared include directory, which is
64 | // dependent on the SDK version. We're gonna find it based on the midl we
65 | // already found.
66 | //
67 | // Our midl path is now something like:
68 | // C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64\midl.exe
69 | //
70 | // We want to get the path to the shared include directory, which is like
71 | //
72 | // C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\shared
73 | //
74 | // (of course, the version number will change depending on the SDK version)
75 | // So, just take that path, remove two elements from the end, replace bin with Include, and add shared.
76 | let mut include_path = PathBuf::from(midl_path.clone());
77 | include_path.pop();
78 | include_path.pop();
79 | // now we're at C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0
80 | let copy_of_include_path = include_path.clone();
81 | let version = copy_of_include_path.file_name().unwrap().to_str().unwrap();
82 | include_path.pop();
83 | include_path.pop();
84 | // now we're at C:\Program Files (x86)\Windows Kits\10\
85 | include_path.push("Include");
86 | include_path.push(version);
87 | include_path.push("shared");
88 |
89 | println!("midl_path: {:?}", midl_path);
90 |
91 | let target = env::var("TARGET").unwrap();
92 |
93 | let cl_path =
94 | cc::windows_registry::find_tool(target.as_str(), "cl.exe").expect("Failed to find cl.exe");
95 | // add cl.exe to our path
96 | let mut path = env::var("PATH").unwrap();
97 | path.push(';');
98 | path.push_str(cl_path.path().parent().unwrap().to_str().unwrap());
99 | env::set_var("PATH", path);
100 |
101 | // Great! we've now finally got a path to midl.exe, and cl.exe is on the PATH
102 |
103 | // Now we can actually run midl.exe, to compile the IDL file. This will
104 | // generate a bunch of files in the OUT_DIR which we need to do RPC.
105 |
106 | let mut cmd = Command::new(midl_path);
107 | cmd.arg("../cpp/rpc/sudo_rpc.idl");
108 | cmd.arg("/h").arg("sudo_rpc.h");
109 | cmd.arg("/target").arg("NT100"); // LOAD BEARING: Enables system_handle
110 | cmd.arg("/acf").arg("../cpp/rpc/sudo_rpc.acf");
111 | cmd.arg("/prefix").arg("client").arg("client_");
112 | cmd.arg("/prefix").arg("server").arg("server_");
113 | cmd.arg("/oldnames");
114 | cmd.arg("/I").arg(include_path);
115 |
116 | // Force midl to use the right architecture depending on our Rust target.
117 | cmd.arg("/env").arg(match target.as_str() {
118 | "x86_64-pc-windows-msvc" => "x64",
119 | "i686-pc-windows-msvc" => "win32",
120 | "aarch64-pc-windows-msvc" => "arm64",
121 | _ => panic!("Unknown target {}", target),
122 | });
123 |
124 | // I was pretty confident that we needed to pass /protocol ndr64 here, but
125 | // if we do that it'll break the win32 build. Omitting it entirely seems to
126 | // Just Work.
127 | // cmd.arg("/protocol").arg("ndr64");
128 |
129 | cmd.arg("/out").arg(env::var("OUT_DIR").unwrap());
130 |
131 | println!("Full midl command: {:?}", cmd);
132 | let mut midl_result = cmd.spawn().expect("Failed to run midl.exe");
133 | println!(
134 | "midl.exe returned {:?}",
135 | midl_result.wait().expect("midl.exe failed")
136 | );
137 |
138 | // Now that our PRC header and stubs were generated, we can compile them
139 | // into our actual RPC lib.
140 | let mut rpc_build = cc::Build::new();
141 | let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
142 | rpc_build
143 | .warnings(true)
144 | .warnings_into_errors(true)
145 | .include(env::var("OUT_DIR").unwrap())
146 | .file(out_dir.join("sudo_rpc_c.c"))
147 | .file(out_dir.join("sudo_rpc_s.c"))
148 | .file("../cpp/rpc/RpcClient.c")
149 | .flag("/guard:ehcont");
150 |
151 | println!("build cmdline: {:?}", rpc_build.get_compiler().to_command());
152 | rpc_build.compile("myRpc");
153 | println!("cargo:rustc-link-lib=myRpc");
154 |
155 | println!("cargo:rerun-if-changed=../cpp/rpc/RpcClient.c");
156 | println!("cargo:rerun-if-changed=../cpp/rpc/sudo_rpc.idl");
157 | }
158 |
159 | fn build_logging() {
160 | // Build our Event Logging library
161 |
162 | let sdk_path: Option = get_sdk_path();
163 | let mc_path = get_sdk_tool(&sdk_path, "mc.exe");
164 |
165 | println!("mc_path: {:?}", mc_path);
166 |
167 | let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
168 |
169 | let mut cmd = Command::new(mc_path);
170 | cmd.arg("-h").arg(&out_dir);
171 | cmd.arg("-r").arg(&out_dir);
172 | cmd.arg("../cpp/logging/instrumentation.man");
173 |
174 | println!("Full mc command: {:?}", cmd);
175 |
176 | let mc_result = cmd
177 | .spawn()
178 | .expect("Failed to run mc.exe")
179 | .wait()
180 | .expect("mc.exe failed");
181 | if !mc_result.success() {
182 | eprintln!("\n\nerror occurred: {}\n\n", mc_result);
183 | std::process::exit(1);
184 | }
185 |
186 | let mut logging_build = cc::Build::new();
187 | logging_build
188 | .warnings(true)
189 | .warnings_into_errors(true)
190 | .include(env::var("OUT_DIR").unwrap())
191 | .file("../cpp/logging/EventViewerLogging.c")
192 | .flag("/guard:ehcont");
193 |
194 | println!(
195 | "build cmdline: {:?}",
196 | logging_build.get_compiler().to_command()
197 | );
198 | logging_build.compile("myEventLogging");
199 | println!("cargo:rustc-link-lib=myEventLogging");
200 |
201 | println!("cargo:rerun-if-changed=../cpp/logging/EventViewerLogging.c");
202 | println!("cargo:rerun-if-changed=../cpp/logging/instrumentation.man");
203 | }
204 |
205 | fn main() -> io::Result<()> {
206 | // Always build the RPC lib.
207 | build_rpc();
208 |
209 | // Always build the Event Logging lib.
210 | build_logging();
211 |
212 | println!("cargo:rerun-if-changed=sudo/Resources/en-US/Sudo.resw");
213 | println!("cargo:rerun-if-changed=sudo.rc");
214 | println!("cargo:rerun-if-changed=../Generated Files/out.rc");
215 | println!("cargo:rerun-if-changed=../Generated Files/out_resources.h");
216 |
217 | // compile the resource file.
218 | // Run
219 | // powershell -c .pipelines\convert-resx-to-rc.ps1 .\ no_existy.h res.h no_existy.rc out.rc resource_ids.rs
220 | // to generate the resources
221 |
222 | let generate_resources_result = Command::new("powershell")
223 | .arg("-NoProfile")
224 | .arg("-c")
225 | .arg("..\\.pipelines\\convert-resx-to-rc.ps1")
226 | .arg("..\\") // Root directory which contains the resx files
227 | .arg("no_existy.h") // File name of the base resource.h which contains all the non-localized resource definitions
228 | .arg("resource.h") // Target file name of the resource header file, which will be used in code - Example: resource.h
229 | .arg("sudo\\sudo.rc") // File name of the base ProjectName.rc which contains all the non-localized resources
230 | .arg("out.rc") // Target file name of the resource rc file, which will be used in code - Example: ProjectName.rc
231 | .arg("resource_ids.rs") // Target file name of the rust resource file, which will be used in code - Example: resource.rs
232 | .status()
233 | .expect("Failed to generate resources");
234 |
235 | if !generate_resources_result.success() {
236 | println!(
237 | "\nFailed to generate resources by executing powershell script: {}.",
238 | generate_resources_result
239 | );
240 | println!(
241 | "Maybe you haven't granted the access to execute the powershell script on this system."
242 | );
243 | println!("For more details, please execute the `cargo build` command with the `-vv` flag.");
244 | std::process::exit(1);
245 | }
246 |
247 | // witchcraft to get windows.h from the SDK to be able to be found, for the resource compiler
248 | let target = env::var("TARGET").unwrap();
249 | if let Some(tool) = cc::windows_registry::find_tool(target.as_str(), "cl.exe") {
250 | for (key, value) in tool.env() {
251 | env::set_var(key, value);
252 | }
253 | }
254 |
255 | if env::var_os("CARGO_CFG_WINDOWS").is_some() {
256 | // TODO:MSFT
257 | // Re-add the following:
258 | //
259 | // detached
260 | //
261 | // to our manifest
262 | embed_manifest_file("sudo.manifest").expect("Failed to embed manifest");
263 |
264 | let generated_rc_content = std::fs::read_to_string("../Generated Files/out.rc").unwrap();
265 | let instrumentation_rc_content =
266 | std::fs::read_to_string(env::var("OUT_DIR").unwrap() + "/instrumentation.rc").unwrap();
267 | let generated_header = std::fs::read_to_string("../Generated Files/resource.h").unwrap();
268 | WindowsResource::new()
269 | // We don't want to use set_resource_file here, because we _do_ want
270 | // the file version info that winres can autogenerate. Instead,
271 | // manually stitch in our generated header (with resource IDs), and
272 | // our generated rc file (with the localized strings)
273 | .append_rc_content(&generated_header)
274 | .append_rc_content(&instrumentation_rc_content)
275 | .append_rc_content(&generated_rc_content)
276 | .compile()?;
277 | }
278 | Ok(())
279 | }
280 |
281 | // Magic incantation to get the build to generate the .rc file, before we build things:
282 | //
283 | // powershell -c .pipelines\convert-resx-to-rc.ps1 src\cascadia\ this_doesnt_exist.h out_resources.h no_existy.rc out.rc resource_ids.rs
284 | //
285 | // do that from the root of the repo, and it will generate the .rc file, into
286 | // src\cascadia\Generated Files\{out.rc, out_resources.h}
287 | //
288 | //
289 | // Alternatively,
290 | // powershell -c .pipelines\convert-resx-to-rc.ps1 .\ no_existy.h res.h no_existy.rc out.rc resource_ids.rs
291 | //
292 | // will generate the .rc file into the a "Generated Files" dir in the root of the repo.
293 |
--------------------------------------------------------------------------------
/sudo/src/elevate_handler.rs:
--------------------------------------------------------------------------------
1 | use crate::helpers::*;
2 | use crate::logging_bindings::event_log_request;
3 | use crate::messages::ElevateRequest;
4 | use crate::rpc_bindings_server::rpc_server_setup;
5 | use crate::tracing;
6 | use std::ffi::CString;
7 | use std::os::windows::io::{FromRawHandle, IntoRawHandle};
8 | use std::os::windows::process::CommandExt;
9 | use std::process::Stdio;
10 | use windows::{
11 | core::*, Win32::Foundation::*, Win32::System::Console::*, Win32::System::Threading::*,
12 | };
13 |
14 | fn handle_to_stdio(h: HANDLE) -> Stdio {
15 | if h.is_invalid() {
16 | return Stdio::inherit();
17 | }
18 |
19 | unsafe {
20 | let p = GetCurrentProcess();
21 | let mut clone = Default::default();
22 | match DuplicateHandle(p, h, p, &mut clone, 0, true, DUPLICATE_SAME_ACCESS) {
23 | Ok(_) => Stdio::from_raw_handle(clone.0 as _),
24 | Err(_) => Stdio::null(),
25 | }
26 | }
27 | }
28 |
29 | /// Prepare the target process, spawn it, and hand back the Child process. This will take care of setting up the handles for redirected input/output, and setting the environment variables.
30 | pub fn spawn_target_for_request(request: &ElevateRequest) -> Result {
31 | tracing::trace_log_message(&format!("Spawning: {}...", &request.application));
32 |
33 | let mut command_args = std::process::Command::new(request.application.clone());
34 |
35 | command_args.current_dir(request.target_dir.clone());
36 | command_args.args(request.args.clone());
37 |
38 | tracing::trace_log_message(&format!("args: {:?}", &request.args));
39 |
40 | if !request.env_vars.is_empty() {
41 | command_args.env_clear();
42 | command_args.envs(env_from_raw_bytes(&request.env_vars));
43 | }
44 |
45 | // If we're in ForceNewWindow mode, we want the target process to use a new
46 | // console window instead of inheriting the one from the parent process.
47 | if request.sudo_mode == SudoMode::ForceNewWindow {
48 | command_args.creation_flags(CREATE_NEW_CONSOLE.0);
49 | }
50 |
51 | // Set the stdin/stdout/stderr of the child process In disabled input
52 | // mode, set stdin to null. We don't want the target application to be
53 | // able to read anything from stdin.
54 | command_args.stdin(if request.sudo_mode != SudoMode::DisableInput {
55 | handle_to_stdio(request.handles[0])
56 | } else {
57 | Stdio::null()
58 | });
59 | command_args.stdout(handle_to_stdio(request.handles[1]));
60 | command_args.stderr(handle_to_stdio(request.handles[2]));
61 |
62 | command_args.spawn().map_err(|err| {
63 | match err.kind() {
64 | std::io::ErrorKind::NotFound => {
65 | // This error code is MSG_DIR_BAD_COMMAND_OR_FILE. That's
66 | // what CMD uses to indicate a command not found.
67 | E_DIR_BAD_COMMAND_OR_FILE.into()
68 | }
69 | _ => err.into(),
70 | }
71 | })
72 | }
73 |
74 | /// Execute the elevation request.
75 | /// * Conditionally attach to the parent process's console (if requested)
76 | /// * Spawn the target process (with redirected input/output if requested, and with the environment variables passed in if needed)
77 | /// Called by rust_handle_elevation_request
78 | pub fn handle_elevation_request(request: &ElevateRequest) -> Result> {
79 | // Log the request we received to the event log. This should create a pair
80 | // of events, one for the request, and one for the response, each with the
81 | // same RequestID.
82 | event_log_request(false, request);
83 |
84 | // Check if the requested sudo mode is allowed
85 | let config: RegistryConfigProvider = Default::default();
86 | let allowed_mode = get_allowed_mode(&config)?;
87 | if request.sudo_mode > allowed_mode {
88 | tracing::trace_log_message(&format!(
89 | "Requested sudo mode is not allowed: {:?} ({:?})",
90 | request.sudo_mode, allowed_mode
91 | ));
92 | return Err(E_ACCESSDENIED.into());
93 | }
94 |
95 | // If we're in ForceNewWindow mode, we _don't_ want to detach from our
96 | // current console and reattach to the parent process's console. Instead,
97 | // we'll just create the target process with CREATE_NEW_CONSOLE.
98 | //
99 | // This scenario only happens when we're running `sudo -E --newWindow`, to
100 | // copy env vars but also use a new console window. If we don't pass -E,
101 | // then we'll have instead just directly ShellExecute'd the target
102 | // application (and never hit this codepath)
103 | //
104 | // Almost all the time, we'll actually hit the body of this conditional.
105 | if request.sudo_mode != SudoMode::ForceNewWindow {
106 | // It would seem that we always need to detach from the current console,
107 | // even in redirected i/o mode. In the case that we aren't fully redirected
108 | // (like, if stdin is redirected but stdout isn't), we'll still need to
109 | // attach to the parent console for the other std handles.
110 |
111 | unsafe {
112 | // Detach from the current console
113 | _ = FreeConsole();
114 |
115 | // Attach to the parent process's console
116 | if { AttachConsole(request.parent_pid) }.is_ok() {
117 | // Add our own CtrlC handler, so that we can ignore it.
118 | _ = SetConsoleCtrlHandler(Some(ignore_ctrl_c), true);
119 | // TODO! add some error handling here you goober
120 | }
121 | }
122 | }
123 |
124 | // We're attached to the right console, Run the command.
125 | let process_launch = spawn_target_for_request(request);
126 | unsafe {
127 | _ = SetConsoleCtrlHandler(Some(ignore_ctrl_c), false);
128 | _ = FreeConsole();
129 | }
130 |
131 | let child = process_launch?;
132 |
133 | // Limit the things the caller can do with the process handle, because the one we just created is PROCESS_ALL_ACCESS.
134 | // I tried to use [out, system_handle(sh_process, PROCESS_QUERY_LIMITED_INFORMATION)]
135 | // in the COM API to have it limit the handle permissions but that didn't work at all.
136 | // So now we do it manually here.
137 | unsafe {
138 | let mut child_handle = Owned::default();
139 | let current_process = GetCurrentProcess();
140 | DuplicateHandle(
141 | current_process,
142 | HANDLE(child.into_raw_handle() as _),
143 | current_process,
144 | &mut *child_handle,
145 | (PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_DUP_HANDLE | PROCESS_SYNCHRONIZE).0,
146 | false,
147 | DUPLICATE_CLOSE_SOURCE,
148 | )?;
149 | Ok(child_handle)
150 | }
151 | }
152 |
153 | /// Starts the RPC server and blocks until Shutdown() is called.
154 | pub fn start_rpc_server(
155 | parent_pid: u32,
156 | nonce: u32,
157 | _caller_sid: Option<&String>,
158 | _args: &[&String],
159 | ) -> Result {
160 | // TODO:48520593 In rust_handle_elevation_request, validate that the parent
161 | // process handle is the same one that we opened here.
162 |
163 | let endpoint = generate_rpc_endpoint_name(parent_pid, nonce);
164 | let endpoint = CString::new(endpoint).unwrap();
165 | rpc_server_setup(&endpoint, parent_pid)?;
166 |
167 | Ok(0)
168 | }
169 |
--------------------------------------------------------------------------------
/sudo/src/logging_bindings.rs:
--------------------------------------------------------------------------------
1 | use crate::helpers::join_args;
2 | use crate::messages::ElevateRequest;
3 | use std::env;
4 | use std::ffi::CString;
5 | use std::mem::size_of_val;
6 | use std::ops::{Deref, DerefMut};
7 | use std::ptr::addr_of;
8 | use windows::core::*;
9 | use windows::Win32::System::Diagnostics::Etw::*;
10 |
11 | // These come from cpp/logging/EventViewerLogging.c
12 | extern "C" {
13 | static PROVIDER_GUID: GUID;
14 | static SudoRequestRunEvent: EVENT_DESCRIPTOR;
15 | static SudoRecieveRunRequestEvent: EVENT_DESCRIPTOR;
16 | }
17 |
18 | #[repr(transparent)]
19 | #[derive(Default)]
20 | struct OwnedReghandle(pub u64);
21 |
22 | impl Drop for OwnedReghandle {
23 | fn drop(&mut self) {
24 | if self.0 != 0 {
25 | unsafe {
26 | EventUnregister(self.0);
27 | }
28 | }
29 | }
30 | }
31 |
32 | impl Deref for OwnedReghandle {
33 | type Target = u64;
34 |
35 | fn deref(&self) -> &Self::Target {
36 | &self.0
37 | }
38 | }
39 |
40 | impl DerefMut for OwnedReghandle {
41 | fn deref_mut(&mut self) -> &mut Self::Target {
42 | &mut self.0
43 | }
44 | }
45 |
46 | fn str_to_cstr_vec>>(s: T) -> Vec {
47 | CString::new(s)
48 | .expect("strings should not have nulls")
49 | .into_bytes_with_nul()
50 | }
51 |
52 | fn create_descriptor(ptr: *const T, len: U) -> EVENT_DATA_DESCRIPTOR
53 | where
54 | U: TryInto,
55 | >::Error: std::fmt::Debug,
56 | {
57 | EVENT_DATA_DESCRIPTOR {
58 | Ptr: ptr as _,
59 | Size: len.try_into().unwrap(),
60 | Anonymous: Default::default(),
61 | }
62 | }
63 |
64 | /// Writes this request to the Windows Event Log. We do this for admins to be
65 | /// able to audit who's calling what with sudo.
66 | /// We log our messages to "Applications and Services Logs" -> "Microsoft" ->
67 | /// "Windows" -> "Sudo" -> "Admin".
68 | ///
69 | /// Alternatively, you can view this log with
70 | /// `wevtutil qe Microsoft-Windows-Sudo/Admin /c:3 /rd:true /f:text`
71 | pub fn event_log_request(is_client: bool, req: &ElevateRequest) {
72 | let mut registration_handle = OwnedReghandle::default();
73 | // The error code returned by EventRegister is primarily intended for use in debugging and diagnostic scenarios.
74 | // Most production code should continue to run even if an ETW provider failed to register,
75 | // so release builds should usually ignore the error code returned by EventRegister.
76 | unsafe { EventRegister(&PROVIDER_GUID, None, None, &mut *registration_handle) };
77 |
78 | let application = str_to_cstr_vec(req.application.as_str());
79 | let args_len = req.args.len() as u32;
80 | let args: Vec<_> = req
81 | .args
82 | .iter()
83 | .map(|arg| str_to_cstr_vec(arg.as_str()))
84 | .collect();
85 | let cwd = str_to_cstr_vec(req.target_dir.as_str());
86 | let mode = req.sudo_mode as u32;
87 | let inherit_env = !req.env_vars.is_empty();
88 | let redirected = req.handles.iter().any(|h| !h.is_invalid());
89 | let commandline = str_to_cstr_vec(format!(
90 | "{} {} {}",
91 | env::current_exe().unwrap().display(),
92 | req.application,
93 | join_args(&req.args)
94 | ));
95 | let request_id = req.event_id;
96 |
97 | let mut descriptors = Vec::with_capacity(9 + args.len());
98 | //
99 | descriptors.push(create_descriptor(application.as_ptr(), application.len()));
100 | //
101 | descriptors.push(create_descriptor(
102 | addr_of!(args_len),
103 | size_of_val(&args_len),
104 | ));
105 | //
106 | for arg in &args {
107 | descriptors.push(EVENT_DATA_DESCRIPTOR {
108 | Ptr: arg.as_ptr() as _,
109 | Size: arg.len() as u32,
110 | Anonymous: Default::default(),
111 | });
112 | }
113 | //
114 | descriptors.push(create_descriptor(cwd.as_ptr(), cwd.len()));
115 | //
116 | descriptors.push(create_descriptor(addr_of!(mode), size_of_val(&mode)));
117 | //
118 | descriptors.push(create_descriptor(
119 | addr_of!(inherit_env),
120 | size_of_val(&inherit_env),
121 | ));
122 | //
123 | descriptors.push(create_descriptor(
124 | addr_of!(redirected),
125 | size_of_val(&redirected),
126 | ));
127 | //
128 | descriptors.push(create_descriptor(commandline.as_ptr(), commandline.len()));
129 | //
130 | descriptors.push(create_descriptor(
131 | addr_of!(request_id),
132 | size_of_val(&request_id),
133 | ));
134 |
135 | unsafe {
136 | // We're literally using the same data template for both requests and
137 | // responses. The only difference is the event ID's have different keywords
138 | // (to ID who sent the event).
139 | let event_id = if is_client {
140 | &SudoRequestRunEvent
141 | } else {
142 | &SudoRecieveRunRequestEvent
143 | };
144 | EventWrite(*registration_handle, event_id, Some(&descriptors));
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/sudo/src/messages.rs:
--------------------------------------------------------------------------------
1 | use crate::helpers::SudoMode;
2 | use windows::{core::GUID, Win32::Foundation::HANDLE};
3 |
4 | pub struct ElevateRequest {
5 | pub parent_pid: u32,
6 | pub handles: [HANDLE; 3], // in, out, err
7 | pub sudo_mode: SudoMode,
8 | pub application: String,
9 | pub args: Vec,
10 | pub target_dir: String,
11 | pub env_vars: String,
12 | pub event_id: GUID,
13 | }
14 |
--------------------------------------------------------------------------------
/sudo/src/r.rs:
--------------------------------------------------------------------------------
1 | //! This file includes all our resource IDs, and the code to load them. The
2 | //! handy string_resources macro does the magic to create a StaticStringResource
3 | //! for each of the resource IDs, and then we can use them in code.
4 | //!
5 | //! Example usage:
6 | //! let world = r::IDS_WORLD.get();
7 | //! println!("Hello: {}", world);
8 |
9 | #![allow(dead_code)]
10 | use win32resources::StaticStringResource;
11 | macro_rules! string_resources {
12 | (
13 | $(
14 | $name:ident = $value:expr ;
15 | )*
16 | ) => {
17 | $(
18 | pub static $name: StaticStringResource = StaticStringResource::new($value, stringify!($name));
19 | )*
20 | }
21 | }
22 |
23 | include!("../../Generated Files/resource_ids.rs");
24 |
--------------------------------------------------------------------------------
/sudo/src/rpc_bindings.rs:
--------------------------------------------------------------------------------
1 | use std::cmp::min;
2 | use std::marker::PhantomData;
3 | use std::slice::from_raw_parts;
4 | use std::str::from_utf8;
5 | use windows::{core::*, Win32::Foundation::*};
6 |
7 | #[repr(C)]
8 | #[derive(Copy, Clone)]
9 | pub struct Utf8Str<'a> {
10 | length: u32,
11 | data: *const u8,
12 | _marker: PhantomData<&'a str>,
13 | }
14 |
15 | impl<'a> Utf8Str<'a> {
16 | pub fn new(s: &str) -> Utf8Str {
17 | Utf8Str {
18 | length: min(s.len(), u32::MAX as usize) as u32,
19 | data: s.as_ptr(),
20 | _marker: PhantomData,
21 | }
22 | }
23 |
24 | pub fn as_str(&self) -> Result<&str> {
25 | from_utf8(unsafe { from_raw_parts(self.data, self.length as usize) })
26 | .map_err(|_| ERROR_NO_UNICODE_TRANSLATION.to_hresult().into())
27 | }
28 | }
29 |
30 | impl<'a> From<&'a str> for Utf8Str<'a> {
31 | fn from(value: &'a str) -> Self {
32 | Utf8Str::new(value)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/sudo/src/rpc_bindings_client.rs:
--------------------------------------------------------------------------------
1 | use crate::helpers::SudoMode;
2 | use crate::rpc_bindings::Utf8Str;
3 | use std::ffi::{c_void, CStr};
4 | use windows::core::{s, GUID, HRESULT, PCSTR, PSTR};
5 | use windows::Win32::Foundation::HANDLE;
6 | use windows::Win32::Storage::FileSystem::{GetFileType, FILE_TYPE_DISK, FILE_TYPE_PIPE};
7 | use windows::Win32::System::Rpc::{
8 | RpcBindingFree, RpcBindingFromStringBindingA, RpcMgmtIsServerListening,
9 | RpcStringBindingComposeA, RpcStringFreeA, RPC_STATUS, RPC_S_OK,
10 | };
11 |
12 | extern "C" {
13 | static mut client_sudo_rpc_ClientIfHandle: *mut c_void;
14 |
15 | fn seh_wrapper_client_DoElevationRequest(
16 | binding: *mut c_void,
17 | parent_handle: HANDLE,
18 | pipe_handles: *const [HANDLE; 3], // in, out, err
19 | file_handles: *const [HANDLE; 3], // in, out, err
20 | sudo_mode: u32,
21 | application: Utf8Str,
22 | args: Utf8Str,
23 | target_dir: Utf8Str,
24 | env_vars: Utf8Str,
25 | event_id: GUID,
26 | child: *mut HANDLE,
27 | ) -> HRESULT;
28 |
29 | fn seh_wrapper_client_Shutdown(binding: *mut c_void) -> HRESULT;
30 | }
31 |
32 | pub fn rpc_client_setup(endpoint: &CStr) -> RPC_STATUS {
33 | unsafe {
34 | let mut string_binding = PSTR::null();
35 | let status = RpcStringBindingComposeA(
36 | /* ObjUuid */ None,
37 | /* ProtSeq */ s!("ncalrpc"),
38 | /* NetworkAddr */ None,
39 | /* Endpoint */ PCSTR(endpoint.as_ptr() as _),
40 | /* Options */ None,
41 | /* StringBinding */ Some(&mut string_binding),
42 | );
43 | if status != RPC_S_OK {
44 | return status;
45 | }
46 |
47 | let status = RpcBindingFromStringBindingA(
48 | PCSTR(string_binding.0),
49 | std::ptr::addr_of_mut!(client_sudo_rpc_ClientIfHandle),
50 | );
51 | // Don't forget to free the previously allocated string before potentially returning. :)
52 | _ = RpcStringFreeA(&mut string_binding);
53 | if status != RPC_S_OK {
54 | return status;
55 | }
56 |
57 | RpcMgmtIsServerListening(Some(client_sudo_rpc_ClientIfHandle))
58 | }
59 | }
60 |
61 | /// Cleans up the RPC server. This is implemented on the server-side in
62 | /// server_Shutdown. It will TerminateProcess the RPC server, really really
63 | /// making sure no one can use it anymore.
64 | pub fn rpc_client_cleanup() {
65 | unsafe {
66 | _ = seh_wrapper_client_Shutdown(client_sudo_rpc_ClientIfHandle);
67 | _ = RpcBindingFree(std::ptr::addr_of_mut!(client_sudo_rpc_ClientIfHandle));
68 | }
69 | }
70 |
71 | #[allow(clippy::too_many_arguments)]
72 | pub fn rpc_client_do_elevation_request(
73 | parent_handle: HANDLE,
74 | handles: &[HANDLE; 3], // in, out, err
75 | sudo_mode: SudoMode,
76 | application: Utf8Str,
77 | args: Utf8Str,
78 | target_dir: Utf8Str,
79 | env_vars: Utf8Str,
80 | event_id: GUID,
81 | child: *mut HANDLE,
82 | ) -> HRESULT {
83 | let mut pipe_handles = [HANDLE::default(); 3];
84 | let mut file_handles = [HANDLE::default(); 3];
85 |
86 | for i in 0..3 {
87 | match unsafe { GetFileType(handles[i]) } {
88 | FILE_TYPE_PIPE => pipe_handles[i] = handles[i],
89 | FILE_TYPE_DISK => file_handles[i] = handles[i],
90 | _ => {}
91 | }
92 | }
93 |
94 | unsafe {
95 | seh_wrapper_client_DoElevationRequest(
96 | client_sudo_rpc_ClientIfHandle,
97 | parent_handle,
98 | &pipe_handles,
99 | &file_handles,
100 | sudo_mode.into(),
101 | application,
102 | args,
103 | target_dir,
104 | env_vars,
105 | event_id,
106 | child,
107 | )
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/sudo/src/rpc_bindings_server.rs:
--------------------------------------------------------------------------------
1 | use crate::helpers::*;
2 | use crate::{
3 | elevate_handler::handle_elevation_request, messages::ElevateRequest, rpc_bindings::Utf8Str,
4 | };
5 | use std::ffi::{c_void, CStr};
6 | use std::mem::{size_of, take};
7 | use std::ptr::null_mut;
8 | use std::sync::atomic::{AtomicBool, Ordering};
9 | use windows::Win32::Foundation::{ERROR_BUSY, GENERIC_ALL, HANDLE, PSID};
10 | use windows::{
11 | core::*, Win32::Security::Authorization::*, Win32::Security::*, Win32::System::Memory::*,
12 | Win32::System::Rpc::*, Win32::System::SystemServices::*, Win32::System::Threading::*,
13 | };
14 |
15 | extern "C" {
16 | static mut server_sudo_rpc_ServerIfHandle: *mut c_void;
17 | }
18 |
19 | static mut EXPECTED_CLIENT_PID: u32 = 0;
20 |
21 | // Process-wide mutex to ensure that only one request is handled at a time. The
22 | // bool inside the atomic is true if we've already started handling a request.
23 | static RPC_SERVER_IN_USE: AtomicBool = AtomicBool::new(false);
24 |
25 | // * Context: The callback function may pass this handle to
26 | // RpcImpersonateClient, RpcBindingServerFromClient,
27 | // RpcGetAuthorizationContextForClient, or any other server side function that
28 | // accepts a client binding handle to obtain information about the client.
29 | //
30 | // The callback function should return RPC_S_OK, if the client is allowed to
31 | // call methods in this interface.
32 | unsafe extern "system" fn rpc_server_callback(
33 | _interface_uuid: *const c_void,
34 | context: *const c_void,
35 | ) -> RPC_STATUS {
36 | let mut client_handle = Owned::default();
37 | let status = I_RpcOpenClientProcess(
38 | Some(context),
39 | PROCESS_QUERY_LIMITED_INFORMATION.0,
40 | &mut *client_handle as *mut _ as _,
41 | );
42 | if status != RPC_S_OK {
43 | return status;
44 | }
45 |
46 | // Check #1: We'll check that the client process is the one we expected,
47 | // when we were first started.
48 | let client_pid = GetProcessId(*client_handle); // if this fails, it returns 0
49 | if client_pid == 0 || client_pid != EXPECTED_CLIENT_PID {
50 | return RPC_S_ACCESS_DENIED;
51 | }
52 |
53 | // Check #2: Check that the client process is the same as the server process.
54 | if check_client(*client_handle).is_err() {
55 | return RPC_S_ACCESS_DENIED;
56 | }
57 |
58 | RPC_S_OK
59 | }
60 |
61 | // MSDN regarding SetSecurityDescriptorSacl:
62 | // > The SACL is referenced by, not copied into, the security descriptor.
63 | // --> To return a SD we need to hold onto everything we allocated. Yay.
64 | #[derive(Default)]
65 | struct OwnedSecurityDescriptor {
66 | pub sd: SECURITY_DESCRIPTOR,
67 | sacl: OwnedLocalAlloc<*mut ACL>,
68 | dacl: OwnedLocalAlloc<*mut ACL>,
69 | }
70 |
71 | // Creates a descriptor of form
72 | // D:(A;;GA;;;)S:(ML;;NWNRNX;;;ME)
73 | fn create_security_descriptor_for_process(pid: u32) -> Result {
74 | unsafe {
75 | let mut s: OwnedSecurityDescriptor = Default::default();
76 | let psd = PSECURITY_DESCRIPTOR(&mut s.sd as *mut _ as _);
77 | InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION)?;
78 |
79 | // SACL
80 | {
81 | let user = {
82 | let process =
83 | Owned::new(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, pid)?);
84 | get_sid_for_process(*process)?
85 | };
86 |
87 | let ea = [EXPLICIT_ACCESS_W {
88 | grfAccessPermissions: GENERIC_ALL.0,
89 | grfAccessMode: SET_ACCESS,
90 | grfInheritance: NO_INHERITANCE,
91 | Trustee: TRUSTEE_W {
92 | pMultipleTrustee: null_mut(),
93 | MultipleTrusteeOperation: NO_MULTIPLE_TRUSTEE,
94 | TrusteeForm: TRUSTEE_IS_SID,
95 | TrusteeType: TRUSTEE_IS_USER,
96 | ptstrName: PWSTR(&user.Sid as *const _ as _),
97 | },
98 | }];
99 |
100 | SetEntriesInAclW(Some(&ea), None, &mut *s.dacl).ok()?;
101 | SetSecurityDescriptorDacl(psd, true, Some(*s.dacl), false)?;
102 | }
103 |
104 | // DACL
105 | {
106 | // windows-rs doesn't have a definition for this macro.
107 | const SECURITY_MAX_SID_SIZE: usize = 88;
108 |
109 | let mut sid_buffer = [0u8; SECURITY_MAX_SID_SIZE];
110 | let mut sid_len = sid_buffer.len() as u32;
111 | let sid = PSID(&mut sid_buffer as *mut _ as _);
112 | CreateWellKnownSid(WinMediumLabelSid, None, sid, &mut sid_len)?;
113 |
114 | const SACL_BUFFER_PREFIX_LEN: usize =
115 | size_of::() + size_of::();
116 | let sacl_len = SACL_BUFFER_PREFIX_LEN as u32 + sid_len;
117 | s.sacl.0 = LocalAlloc(LMEM_FIXED, sacl_len as usize)?.0 as _;
118 |
119 | InitializeAcl(*s.sacl, sacl_len, ACL_REVISION)?;
120 | AddMandatoryAce(
121 | *s.sacl,
122 | ACL_REVISION,
123 | ACE_FLAGS(0),
124 | SYSTEM_MANDATORY_LABEL_NO_READ_UP
125 | | SYSTEM_MANDATORY_LABEL_NO_WRITE_UP
126 | | SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP,
127 | sid,
128 | )?;
129 |
130 | SetSecurityDescriptorSacl(psd, true, Some(*s.sacl), false)?;
131 | }
132 |
133 | Ok(s)
134 | }
135 | }
136 |
137 | pub fn rpc_server_setup(endpoint: &CStr, expected_client_pid: u32) -> Result<()> {
138 | let owned_sd = create_security_descriptor_for_process(expected_client_pid)?;
139 |
140 | unsafe {
141 | RpcServerUseProtseqEpA(
142 | /* Protseq */ s!("ncalrpc"),
143 | /* MaxCalls */ RPC_C_LISTEN_MAX_CALLS_DEFAULT,
144 | /* Endpoint */ PCSTR(endpoint.as_ptr() as _),
145 | /* SecurityDescriptor */ Some(&owned_sd.sd as *const _ as _),
146 | )
147 | .ok()?;
148 | RpcServerRegisterIf3(
149 | /* IfSpec */ server_sudo_rpc_ServerIfHandle,
150 | /* MgrTypeUuid */ None,
151 | /* MgrEpv */ None,
152 | /* Flags */ RPC_IF_ALLOW_LOCAL_ONLY | RPC_IF_ALLOW_SECURE_ONLY,
153 | /* MaxCalls */ RPC_C_LISTEN_MAX_CALLS_DEFAULT,
154 | /* MaxRpcSize */ u32::MAX,
155 | /* IfCallback */ Some(rpc_server_callback),
156 | /* SecurityDescriptor */ Some(&owned_sd.sd as *const _ as _),
157 | )
158 | .ok()?;
159 |
160 | EXPECTED_CLIENT_PID = expected_client_pid;
161 |
162 | let res = RpcServerListen(
163 | /* MinimumCallThreads */ 1,
164 | /* MaxCalls */ RPC_C_LISTEN_MAX_CALLS_DEFAULT,
165 | /* DontWait */ 0,
166 | );
167 | if res.is_err() {
168 | _ = RpcServerUnregisterIf(None, None, 0);
169 | }
170 | res.ok()
171 | }
172 | }
173 |
174 | // This is the RPC's sudo_rpc::Shutdown callback function.
175 | #[no_mangle]
176 | unsafe extern "C" fn server_Shutdown(_binding: *const c_void) {
177 | _ = TerminateProcess(GetCurrentProcess(), 0);
178 | }
179 |
180 | // This is the RPC's sudo_rpc::DoElevationRequest callback function.
181 | #[no_mangle]
182 | pub extern "C" fn server_DoElevationRequest(
183 | _binding: *const c_void,
184 | parent_handle: HANDLE,
185 | pipe_handles: *const [HANDLE; 3], // in, out, err
186 | file_handles: *const [HANDLE; 3], // in, out, err
187 | sudo_mode: u32,
188 | application: Utf8Str,
189 | args: Utf8Str,
190 | target_dir: Utf8Str,
191 | env_vars: Utf8Str,
192 | event_id: GUID,
193 | child: *mut HANDLE,
194 | ) -> HRESULT {
195 | // Only the first caller will get their request handled. Everyone else will
196 | // be forced to bail out.
197 | if RPC_SERVER_IN_USE.swap(true, Ordering::Relaxed) {
198 | // We're already in the middle of handling a request.
199 | return ERROR_BUSY.to_hresult();
200 | }
201 |
202 | // Here, we've locked the mutex and we're the only ones handling a request.
203 | //
204 | // And, we've set the atom to true, so if someone _does_ connect to us after
205 | // this function releases the lock, then they'll also bail out.
206 |
207 | // Immediately unregister ourself. This will prevent a future caller from
208 | // getting to us (but won't cancel the current request we're already in the
209 | // middle of replying to).
210 | unsafe {
211 | _ = RpcMgmtStopServerListening(None);
212 | _ = RpcServerUnregisterIf(None, None, 0);
213 | }
214 |
215 | let result = wrap_elevate_request(
216 | parent_handle,
217 | pipe_handles,
218 | file_handles,
219 | sudo_mode,
220 | application,
221 | args,
222 | target_dir,
223 | env_vars,
224 | event_id,
225 | )
226 | .and_then(|req| handle_elevation_request(&req));
227 |
228 | match result {
229 | Ok(mut handle) => {
230 | unsafe { child.write(take(&mut handle)) };
231 | HRESULT::default()
232 | }
233 | Err(err) => err.into(),
234 | }
235 | }
236 |
237 | #[allow(clippy::too_many_arguments)]
238 | fn wrap_elevate_request(
239 | parent_handle: HANDLE,
240 | pipe_handles: *const [HANDLE; 3], // in, out, err
241 | file_handles: *const [HANDLE; 3], // in, out, err
242 | sudo_mode: u32,
243 | application: Utf8Str,
244 | args: Utf8Str,
245 | target_dir: Utf8Str,
246 | env_vars: Utf8Str,
247 | event_id: GUID,
248 | ) -> Result {
249 | let parent_pid = unsafe { GetProcessId(parent_handle) };
250 | let handles = unsafe {
251 | let pipes = &*pipe_handles;
252 | let files = &*file_handles;
253 | std::array::from_fn(|i| if pipes[i].0 != 0 { pipes[i] } else { files[i] })
254 | };
255 |
256 | Ok(ElevateRequest {
257 | parent_pid,
258 | handles,
259 | sudo_mode: sudo_mode.try_into()?,
260 | application: application.as_str()?.to_owned(),
261 | args: unpack_string_list_from_rpc(args)?,
262 | target_dir: target_dir.as_str()?.to_owned(),
263 | env_vars: env_vars.as_str()?.to_owned(),
264 | event_id,
265 | })
266 | }
267 |
268 | #[cfg(test)]
269 | mod tests {
270 | use super::*;
271 |
272 | #[test]
273 | fn test_create_security_descriptor_for_process() {
274 | fn sd_to_string(sd: PSECURITY_DESCRIPTOR) -> Result {
275 | unsafe {
276 | let mut buffer = PSTR::null();
277 | ConvertSecurityDescriptorToStringSecurityDescriptorA(
278 | sd,
279 | SDDL_REVISION,
280 | DACL_SECURITY_INFORMATION
281 | | LABEL_SECURITY_INFORMATION
282 | | OWNER_SECURITY_INFORMATION,
283 | &mut buffer,
284 | None,
285 | )?;
286 | Ok(buffer.to_string()?)
287 | }
288 | }
289 |
290 | let s = create_security_descriptor_for_process(unsafe { GetCurrentProcessId() }).unwrap();
291 | let str = sd_to_string(PSECURITY_DESCRIPTOR(&s.sd as *const _ as _)).unwrap();
292 | assert!(str.starts_with("D:(A;;GA;;;"));
293 | assert!(str.ends_with(")S:(ML;;NWNRNX;;;ME)"));
294 | }
295 | }
296 |
--------------------------------------------------------------------------------
/sudo/src/tests/mod.rs:
--------------------------------------------------------------------------------
1 | #[cfg(test)]
2 | mod tests {
3 | use crate::helpers::*;
4 | use windows::Win32::Foundation::*;
5 |
6 | #[test]
7 | fn test_try_from_u32_for_sudo_mode() {
8 | assert_eq!(SudoMode::try_from(0), Ok(SudoMode::Disabled));
9 | assert_eq!(SudoMode::try_from(1), Ok(SudoMode::ForceNewWindow));
10 | assert_eq!(SudoMode::try_from(2), Ok(SudoMode::DisableInput));
11 | assert_eq!(SudoMode::try_from(3), Ok(SudoMode::Normal));
12 | assert_eq!(SudoMode::try_from(4), Err(ERROR_INVALID_PARAMETER.into()));
13 | }
14 | #[test]
15 | fn test_try_sudo_mode_to_u32() {
16 | assert_eq!(u32::from(SudoMode::Disabled), 0);
17 | assert_eq!(u32::from(SudoMode::ForceNewWindow), 1);
18 | assert_eq!(u32::from(SudoMode::DisableInput), 2);
19 | assert_eq!(u32::from(SudoMode::Normal), 3);
20 | }
21 |
22 | #[test]
23 | fn test_generate_rpc_endpoint_name() {
24 | assert_eq!(
25 | generate_rpc_endpoint_name(1234, 2345),
26 | r"sudo_elevate_1234_2345"
27 | );
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/sudo/src/tracing.rs:
--------------------------------------------------------------------------------
1 | use sudo_events::SudoEvents;
2 |
3 | // tl:{6ffdd42d-46d9-5efe-68a1-3b18cb73a607}
4 | static SUDO_EVENTS: std::sync::OnceLock = std::sync::OnceLock::new();
5 |
6 | const PDT_PRODUCT_AND_SERVICE_PERFORMANCE: u64 = 0x0000000001000000;
7 | // const PDT_PRODUCT_AND_SERVICE_USAGE: u64 = 0x0000000002000000;
8 |
9 | pub fn sudo_events() -> &'static SudoEvents {
10 | SUDO_EVENTS.get_or_init(SudoEvents::new)
11 | }
12 |
13 | use crate::messages::*;
14 |
15 | pub fn enable_tracing() {
16 | sudo_events();
17 | }
18 |
19 | pub fn trace_log_message(message: &str) {
20 | sudo_events().message(None, message);
21 | }
22 |
23 | pub fn trace_command_not_found(exe_name: &str) {
24 | sudo_events().command_not_found(None, exe_name);
25 | }
26 |
27 | pub fn trace_cmd_builtin_found(exe_name: &str) {
28 | sudo_events().cmd_builtin_found(None, exe_name);
29 | }
30 |
31 | pub fn trace_run(req: &ElevateRequest, redirected_input: bool, redirected_output: bool) {
32 | sudo_events().run(
33 | None,
34 | &req.application,
35 | req.sudo_mode as u32,
36 | req.parent_pid,
37 | redirected_input,
38 | redirected_output,
39 | );
40 | }
41 |
42 | pub fn trace_modes(requested_mode: u32, allowed_mode: u32, policy_mode: u32) {
43 | // We manually set the privacy tag to PDT_PRODUCT_AND_SERVICE_PERFORMANCE so
44 | // that callers don't need to know that
45 | sudo_events().modes(
46 | None,
47 | requested_mode,
48 | allowed_mode,
49 | policy_mode,
50 | PDT_PRODUCT_AND_SERVICE_PERFORMANCE,
51 | );
52 | }
53 |
--------------------------------------------------------------------------------
/sudo/sudo.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | true
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/sudo/sudo.rc:
--------------------------------------------------------------------------------
1 | // Resource file (.rc) template for sudo.
2 | //
3 | // Our string resources are all auto-generated from our resw file. They'll be
4 | // consumed from a generated .rc file, which will start with the content of this file.
5 |
6 | #include
7 |
8 | // Here, you'd usually want to
9 | //
10 | // #include "resource.h"
11 | //
12 | // To include your resource ID's. That doesn't work for us!
13 | // We want to use the winres crate to auto-generate FILEVERSION et. al. If we
14 | // want that to work, then we need to append the content of our generated file
15 | // to the content winres generates (using append_rc_content).
16 | // However, when we do it that way, the ultimate .rc file we end up using is one
17 | // that's generated in our OUT_DIR, and that means it can't find the relative
18 | // resource.h
19 | //
20 | // Instead, we'll use append_rc_content to _also_ include the header literally
21 | // in the output .rc file.
22 |
23 | // Make sure to declare our exe icon here
24 | IDI_APPICON ICON "..\\img\\ico\\sudo.ico"
25 |
--------------------------------------------------------------------------------
/sudo_events/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "sudo_events"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | [dependencies]
7 | win_etw_macros.workspace = true
8 | win_etw_provider.workspace = true
9 |
--------------------------------------------------------------------------------
/sudo_events/build.rs:
--------------------------------------------------------------------------------
1 | use std::{io, path::Path};
2 |
3 | // BODGY
4 | //
5 | // * As a part of the build process, we need to replace the fake GUID in our
6 | // tracing lib with the real one.
7 | // * This build script here will take the value out of the env var
8 | // MAGIC_TRACING_GUID, and replace the fake GUID in the events_template.rs
9 | // file with that one.
10 | // * We'll write that file out to %OUT_DIR%/mangled_events.rs, and then include
11 | // _that mangled file_ in our lib.rs file.
12 | fn main() -> io::Result<()> {
13 | let input = std::fs::read_to_string("src/events_template.rs")?;
14 | // Is the MAGIC_TRACING_GUID env var set? If it is...
15 | let output = match std::env::var("MAGIC_TRACING_GUID") {
16 | Ok(guid) => {
17 | println!("MAGIC_TRACING_GUID: {}", guid);
18 |
19 | // Replace the fake guid (ffffffff-ffff-ffff-ffff-ffffffffffff) with this one.
20 |
21 | input.replace("ffffffff-ffff-ffff-ffff-ffffffffffff", &guid)
22 | }
23 | Err(_) => input,
24 | };
25 | let path = Path::new(&std::env::var("OUT_DIR").unwrap()).join("mangled_events.rs");
26 | println!(
27 | "cargo:rerun-if-changed={}",
28 | path.as_path().to_str().unwrap()
29 | );
30 | std::fs::write(path.as_path(), output)
31 | }
32 |
--------------------------------------------------------------------------------
/sudo_events/src/events_template.rs:
--------------------------------------------------------------------------------
1 |
2 | use win_etw_macros::trace_logging_provider;
3 | // Note: Generate GUID using TlgGuid.exe tool
4 | #[trace_logging_provider(
5 | name = "Microsoft.Windows.Sudo",
6 | guid = "6ffdd42d-46d9-5efe-68a1-3b18cb73a607",
7 | provider_group_guid = "ffffffff-ffff-ffff-ffff-ffffffffffff"
8 | )]
9 | // tl:{6ffdd42d-46d9-5efe-68a1-3b18cb73a607}
10 |
11 | pub trait SudoEvents {
12 | fn command_not_found(exe_name: &str);
13 |
14 | fn cmd_builtin_found(exe_name: &str);
15 |
16 | fn message(message: &str);
17 |
18 | fn run(
19 | exe_name: &str,
20 | requested_mode: u32,
21 | parent_pid: u32,
22 | redirected_input: bool,
23 | redirected_output: bool,
24 | );
25 |
26 | // TRACELOGGING EVENTS:
27 | //
28 | // These events need to add a PartA_PrivTags: u64 parameter to the end of
29 | // the event. That should be filled with PDT_ProductAndServicePerformance or
30 | // PDT_ProductAndServiceUsage. Our wrappers in tracing.rs should abstract
31 | // that away.
32 | //
33 | // Additionally, we manually set the keyword to MICROSOFT_KEYWORD_MEASURES.
34 | // However, we can't use that constant here, because the macro needs an
35 | // actual _literal_. So, we use the value 0x0000400000000000 directly.
36 | // MICROSOFT_KEYWORD_TELEMETRY is 0x0000200000000000, but that... doesn't work?
37 |
38 | // requested_mode:
39 | // * 0: Use the allowed mode from the registry / policy
40 | // * 1: Manually request forceNewWindow
41 | // * 2: Manually request disableInput
42 | // * 3: ??? We shouldn't get these. Requested mode is set by the CLI flags
43 | // allowed_mode: Straightforward. The mode in the registry
44 | // policy_mode: The mode set by the policy. If the policy isn't set, this should be 0xffffffff
45 | #[event(keyword = 0x0000400000000000)]
46 | fn modes(requested_mode: u32, allowed_mode: u32, policy_mode: u32, PartA_PrivTags: u64);
47 | }
48 |
--------------------------------------------------------------------------------
/sudo_events/src/lib.rs:
--------------------------------------------------------------------------------
1 | include!(concat!(env!("OUT_DIR"), "/mangled_events.rs"));
2 |
--------------------------------------------------------------------------------
/tools/gen-lang-codes.ps1:
--------------------------------------------------------------------------------
1 | # This is a list of what I think all the languages we need to support are. At
2 | # the very least, it's all the languages that the Terminal's context menu are
3 | # localized into. If we need more than that, go ahead and add more. This has to
4 | # be the most complete list - the script that actually generates the .rc file
5 | # will use whatever subest of languages are actually available.
6 |
7 | $languageCodes = @(
8 | "af-ZA",
9 | "am-ET",
10 | "ar-SA",
11 | "as-IN",
12 | "az-Latn-AZ",
13 | "bg-BG",
14 | "bn-IN",
15 | "bs-Latn-BA",
16 | "ca-ES",
17 | "ca-Es-VALENCIA",
18 | "cs-CZ",
19 | "cy-GB",
20 | "da-DK",
21 | "de-DE",
22 | "el-GR",
23 | "en-GB",
24 | "en-US",
25 | "es-ES",
26 | "es-MX",
27 | "et-EE",
28 | "eu-ES",
29 | "fa-IR",
30 | "fi-FI",
31 | "fil-PH",
32 | "fr-CA",
33 | "fr-FR",
34 | "ga-IE",
35 | "gd-gb",
36 | "gl-ES",
37 | "gu-IN",
38 | "he-IL",
39 | "hi-IN",
40 | "hr-HR",
41 | "hu-HU",
42 | "hy-AM",
43 | "id-ID",
44 | "is-IS",
45 | "it-IT",
46 | "ja-JP",
47 | "ka-GE",
48 | "kk-KZ",
49 | "km-KH",
50 | "kn-IN",
51 | "ko-KR",
52 | "kok-IN",
53 | "lb-LU",
54 | "lo-LA",
55 | "lt-LT",
56 | "lv-LV",
57 | "mi-NZ",
58 | "mk-MK",
59 | "ml-IN",
60 | "mr-IN",
61 | "ms-MY",
62 | "mt-MT",
63 | "nb-NO",
64 | "ne-NP",
65 | "nl-NL",
66 | "nn-NO",
67 | "or-IN",
68 | "pa-IN",
69 | "pl-PL",
70 | "pt-BR",
71 | "pt-PT",
72 | "qps-ploc",
73 | "qps-ploca",
74 | "qps-plocm",
75 | "quz-PE",
76 | "ro-RO",
77 | "ru-RU",
78 | "sk-SK",
79 | "sl-SI",
80 | "sq-AL",
81 | "sr-Cyrl-BA",
82 | "sr-Cyrl-RS",
83 | "sr-Latn-RS",
84 | "sv-SE",
85 | "ta-IN",
86 | "te-IN",
87 | "th-TH",
88 | "tr-TR",
89 | "tt-RU",
90 | "ug-CN",
91 | "uk-UA",
92 | "ur-PK",
93 | "uz-Latn-UZ",
94 | "vi-VN",
95 | "zh-CN",
96 | "zh-TW"
97 | )
98 |
99 | function Get-Language-Sublanguage-Constants {
100 | param (
101 | [int]$lcid
102 | )
103 |
104 | $language = $lcid -band 0xFFFF
105 | $sublanguage = ($lcid -shr 16) -band 0x3F
106 |
107 | # Language Constants
108 | $languageConstant = "LANG_" + ([System.Globalization.CultureInfo]::GetCultureInfo($lcid).TwoLetterISOLanguageName).ToUpper()
109 |
110 | # Sublanguage Constants
111 | $sublanguageConstant = "SUBLANG_" + ([System.Globalization.CultureInfo]::GetCultureInfo($lcid).Name.Split('-')[1]).ToUpper()
112 |
113 | return $language, $sublanguage, $languageConstant, $sublanguageConstant, ([System.Globalization.CultureInfo]::GetCultureInfo($lcid).ThreeLetterISOLanguageName).ToUpper()
114 | }
115 |
116 | $languageHashTable = @{}
117 |
118 | foreach ($code in $languageCodes) {
119 | $cultureInfo = New-Object System.Globalization.CultureInfo $code
120 | $displayName = $cultureInfo.DisplayName
121 | $neutralCulture = $cultureInfo.Parent.Name
122 | $lcid = $cultureInfo.LCID
123 | $language, $sublanguage, $languageConstant, $sublanguageConstant, $threeLetter = Get-Language-Sublanguage-Constants -lcid $lcid
124 |
125 | # trim out "LANG_" and "SUBLANG_
126 | $languageConstant = $languageConstant.Substring(5)
127 | $sublanguageConstant = $sublanguageConstant.Substring(8)
128 |
129 | $hashTableValue = @(
130 | # $cultureInfo.Name.ToUpper(),
131 | # "",
132 | $threeLetter,
133 | $language,
134 | $sublanguage, # $cultureInfo.Name.ToUpper() + '_' + $cultureInfo.Parent.Name.ToUpper(),
135 | $displayName
136 | )
137 |
138 | $languageHashTable[$code] = $hashTableValue
139 | }
140 | # write list like:
141 | #
142 | # "eu-ES" = @("EUQ", "BASQUE", "DEFAULT", "Basque (Basque)");
143 | # $languageHashTable | % {
144 |
145 | foreach ($code in $languageCodes) {
146 | $lang = $languageHashTable[$code]
147 | # Get language and sublanguage constants
148 |
149 | write-host " `"$($code)`" = @(`"$($lang[0])`", `"$($lang[1])`", `"$($lang[2])`", `"$($lang[3])`");"
150 |
151 | # if ($_.Value -ne $null ) {
152 | # write-host " `"$($_.Key)`" = @(`"$($_.Value[0])`", `"$($_.Value[1])`", `"$($_.Value[2])`", `"$($_.Value[3])`");" }
153 | }
154 |
--------------------------------------------------------------------------------
/tools/sudo.tvpp:
--------------------------------------------------------------------------------
1 |
2 |
3 | LocalLive
4 | sudo for windows
5 |
6 | tl:{6ffdd42d-46d9-5efe-68a1-3b18cb73a607}
7 |
8 |
9 |
10 | 6ffdd42d-46d9-5efe-68a1-3b18cb73a607
11 | 0
12 | 0
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/win32resources/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "win32resources"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
--------------------------------------------------------------------------------
/win32resources/src/lib.rs:
--------------------------------------------------------------------------------
1 | //! Provides APIs for accessing Win32 resources, mainly string resources.
2 | use std::borrow::Cow;
3 | use std::ffi::c_void;
4 | use std::ops::Deref;
5 | use std::ptr::null_mut;
6 | use std::slice::from_raw_parts;
7 | use std::sync::OnceLock;
8 |
9 | #[allow(clippy::upper_case_acronyms)]
10 | type HINSTANCE = *const c_void;
11 |
12 | extern "system" {
13 | fn LoadStringW(hInstance: HINSTANCE, uID: u32, lpBuffer: *mut u16, cchBufferMax: i32) -> i32;
14 | }
15 |
16 | extern "C" {
17 | static __ImageBase: [u8; 0];
18 | }
19 |
20 | fn module_base() -> *const c_void {
21 | unsafe { (&__ImageBase) as *const [u8; 0] as *const c_void }
22 | }
23 |
24 | /*
25 | #[macro_export]
26 | macro_rules! def_image_base {
27 | (
28 | $fn_name:ident
29 | ) => {
30 | fn $fn_name() -> &'static ModuleAddress {
31 | extern "C" {
32 | static _ImageBase: ();
33 | }
34 | (&_ImageBase) as *const () as *const core::ffi::c_void
35 | }
36 | }
37 | }
38 | */
39 |
40 | pub struct StaticStringResource {
41 | id: u32,
42 | value: OnceLock>,
43 | fallback: &'static str,
44 | }
45 |
46 | impl StaticStringResource {
47 | pub const fn new(id: u32, fallback: &'static str) -> Self {
48 | Self {
49 | id,
50 | value: OnceLock::new(),
51 | fallback,
52 | }
53 | }
54 |
55 | pub fn get(&self) -> &str {
56 | self.value.get_or_init(|| {
57 | let image_base = module_base();
58 |
59 | // If this returns 0, then the string was not found.
60 | let mut base: *const u16 = null_mut();
61 | let len = unsafe { LoadStringW(image_base, self.id, &mut base as *mut _ as *mut _, 0) };
62 | if len <= 0 {
63 | return Cow::Borrowed(self.fallback);
64 | }
65 |
66 | Cow::Owned(String::from_utf16_lossy(unsafe {
67 | from_raw_parts(base, len as usize)
68 | }))
69 | })
70 | }
71 | }
72 |
73 | impl Deref for StaticStringResource {
74 | type Target = str;
75 |
76 | fn deref(&self) -> &Self::Target {
77 | self.get()
78 | }
79 | }
80 |
--------------------------------------------------------------------------------