Commit a8ff99b1 authored by Josh Wisenbaker's avatar Josh Wisenbaker

Merge branch 'DastardlyDaikon' into 'master'

1.2.3 Release

See merge request !60
parents 53208462 f463f6fe
Pipeline #47440893 passed with stage
in 4 minutes and 11 seconds
......@@ -7,6 +7,7 @@
enum HintType: String {
case networkSignIn
case noMADUser
case noMADDomain
case noMADPass
......@@ -19,6 +20,11 @@ enum HintType: String {
case kerberos_principal
// attribute statics
let kODAttributeADUser = "dsAttrTypeStandard:ADUser"
let kODAttributeNetworkSignIn = "dsAttrTypeStandard:NetworkSignIn"
protocol ContextAndHintHandling {
var mech: MechanismRecord? {get}
func setContextString(type: String, value: String)
......@@ -20,3 +20,7 @@ let enableFDELog = OSLog(subsystem: "", category: "EnableFDEL
let sierraFixesLog = OSLog(subsystem: "", category: "SierraFixesLog")
let keychainAddLog = OSLog(subsystem: "", category: "KeychainAdd")
let eulaLog = OSLog(subsystem: "", category: "EULA")
let runScriptLog = OSLog(subsystem: "menu.nomad.login", category: "RunScript")
let notifyLog = OSLog(subsystem: "menu.nomad.login", category: "Notify")
let settingsLog = OSLog(subsystem: "menu.nomad.login", category: "Settings")
let userinputLog = OSLog(subsystem: "menu.nomad.login", category: "UserInput")
......@@ -46,6 +46,9 @@ struct MechanismRecord {
Boolean fEnableFDE;
Boolean fSierraFixes;
Boolean fEULA;
Boolean fUserInput;
Boolean fRunScript;
Boolean fNotify;
typedef struct MechanismRecord MechanismRecord;
......@@ -100,7 +100,11 @@ extern OSStatus AuthorizationPluginCreate(const AuthorizationCallbacks *callback
mechanism->fEnableFDE = (strcmp(mechanismId, "EnableFDE") == 0);
mechanism->fSierraFixes = (strcmp(mechanismId, "SierraFixes") == 0);
mechanism->fEULA = (strcmp(mechanismId, "EULA") == 0);
mechanism->fUserInput = (strcmp(mechanismId, "UserInput") == 0);
mechanism->fNotify = (strcmp(mechanismId, "Notify") == 0);
mechanism->fRunScript = (strcmp(mechanismId, "RunScript") == 0);
*outMechanism = mechanism;
os_log_debug(pluginLog, "NoLoPlugin:MechanismCreate: inPlugin=%p, inEngine=%p, mechanismId='%{public}s'", inPlugin, inEngine, mechanismId);
return errSecSuccess;
......@@ -152,7 +156,23 @@ extern OSStatus AuthorizationPluginCreate(const AuthorizationCallbacks *callback
EULA * eula = [[EULA alloc] initWithMechanism:mechanism];
[eula run];
NSLog(@"EULA done");
} else if (mechanism->fRunScript) {
NSLog(@"Calling RunScript");
RunScript * runScript = [[RunScript alloc] initWithMechanism:mechanism];
[runScript run];
NSLog(@"RunScript done");
} else if (mechanism->fNotify) {
NSLog(@"Calling Notify");
Notify * notify = [[Notify alloc] initWithMechanism:mechanism];
[notify run];
NSLog(@"Notify done");
} else if (mechanism->fUserInput) {
NSLog(@"Calling User Input");
UserInput * userInput = [[UserInput alloc] initWithMechanism:mechanism];
[userInput run];
NSLog(@"User Input done");
return noErr;
......@@ -15,6 +15,8 @@ enum Preferences: String {
case AdditionalADDomains
/// A filesystem path to a background image as a `String`.
case BackgroundImage
/// An image to display as the background image as a Base64 encoded `String`.
case BackgroundImageData
/// The alpha value of the background image as an `Int`.
case BackgroundImageAlpha
/// Should new users be created as local administrators? Set as a `Bool`.
......@@ -23,10 +25,20 @@ enum Preferences: String {
case CreateAdminIfGroupMember
/// Should existing mobile accounts be converted into plain local accounts? Set as a Bool`.
case DemobilizeUsers
/// Dissallow local auth, and always do network authentication
case DenyLocal
/// Users to allow locally when DenyLocal is on
case DenyLocalExcluded
/// List of groups that should have it's members allowed to sign in. Set as an Array of Strings of the group name
case DenyLoginUnlessGroupMember
/// Should FDE be enabled at first login on APFS disks? Set as a `Bool`.
case EnableFDE
/// Should the PRK be saved to disk for the MDM Escrow Service to collect? Set as a `Bool`.
case EnableFDERecoveryKey
// Specify a custom path for the recovery key
case EnableFDERecoveryKeyPath
// Should we rotate the PRK
case EnableFDERekey
/// Path for where the EULA acceptance info goes
case EULAPath
/// Text for EULA as a `String`.
......@@ -45,16 +57,38 @@ enum Preferences: String {
case KeychainReset
/// Force LDAP lookups to use SSL connections. Requires certificate trust be established. Set as a `Bool`.
case LDAPOverSSL
/// Force specific LDAP servers instead of finding them via DNS
case LDAPServers
/// Fallback to local auth if the network is not available
case LocalFallback
/// A filesystem path to an image to display on the login screen as a `String`.
case LoginLogo
/// Alpha value for the login logo
case LoginLogoAlpha
/// A Base64 encoded string of an image to display on the login screen.
case LoginLogoData
/// Should NoLo display a macOS-style login screen instead of a window? Set as a `Bool`,
case LoginScreen
/// If Notify should add additional logging
case NotifyLogStyle
/// Path to script to run, currently only one script path can be used, if you want to run this multiple times, keep the logic in your script
case ScriptPath
/// Arguments for the script, if any
case ScriptArgs
/// Use the CN from AD as the full name
case UseCNForFullName
/// A string to show as the placeholder in the Username textfield
case UsernameFieldPlaceholder
/// A filesystem path to an image to set the user profile image to as a `String`
case UserProfileImage
//UserInput bits
case UserInputOutputPath
case UserInputUI
case UserInputLogo
case UserInputTitle
case UserInputMainText
......@@ -64,23 +98,27 @@ enum Preferences: String {
/// - Parameter key: A member of the `Preferences` enum
/// - Returns: The value, if any, for the preference. If no preference is set, returns `nil`
func getManagedPreference(key: Preferences) -> Any? {
if let preference = UserDefaults(suiteName: "com.trusourcelabs.NoMAD")?.value(forKey: key.rawValue) {
os_log("Checking preference domain.", type: .debug)
if let preference = UserDefaults(suiteName: "")?.value(forKey: key.rawValue) {
os_log("Found managed preference: %{public}@", type: .debug, key.rawValue)
return preference
os_log("No NoMAD preferences found. Checking NoLoAD", type: .debug)
os_log("No preference found. Checking menu.nomad.NoMADLoginAD", type: .debug)
if let preference = UserDefaults(suiteName: "menu.nomad.NoMADLoginAD")?.value(forKey: key.rawValue) {
os_log("Found managed preference: %{public}@", type: .debug, key.rawValue)
return preference
os_log("No menu.nomad.NoMADLoginAD preference found. Checking com.trusourcelabs.NoMAD", type: .debug)
os_log("No NoLoAD preferences found. Checking new", type: .debug)
if let preference = UserDefaults(suiteName: "")?.value(forKey: key.rawValue) {
if let preference = UserDefaults(suiteName: "com.trusourcelabs.NoMAD")?.value(forKey: key.rawValue) {
os_log("Found managed preference: %{public}@", type: .debug, key.rawValue)
return preference
return nil
"Mac" : [
"name" : "NoMAD_ADAuth",
"hash" : "d15a5ad01c1b4f6a6fcdbeccef7a3661649a3c6b7a5c65d690dd42812b9467bb"
"watchOS" : [
"tvOS" : [
"commitish" : "1.0.4",
"iOS" : [
\ No newline at end of file
\ No newline at end of file
\ No newline at end of file
\ No newline at end of file
\ No newline at end of file
// Generated by Apple Swift version 4.2.1 (swiftlang-1000.11.42 clang-1000.11.45.1)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgcc-compat"
#if !defined(__has_include)
# define __has_include(x) 0
#if !defined(__has_attribute)
# define __has_attribute(x) 0
#if !defined(__has_feature)
# define __has_feature(x) 0
#if !defined(__has_warning)
# define __has_warning(x) 0
#if __has_include(<swift/objc-prologue.h>)
# include <swift/objc-prologue.h>
#pragma clang diagnostic ignored "-Wauto-import"
#include <objc/NSObject.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#if !defined(SWIFT_TYPEDEFS)
# if __has_include(<uchar.h>)
# include <uchar.h>
# elif !defined(__cplusplus)
typedef uint_least16_t char16_t;
typedef uint_least32_t char32_t;
# endif
typedef float swift_float2 __attribute__((__ext_vector_type__(2)));
typedef float swift_float3 __attribute__((__ext_vector_type__(3)));
typedef float swift_float4 __attribute__((__ext_vector_type__(4)));
typedef double swift_double2 __attribute__((__ext_vector_type__(2)));
typedef double swift_double3 __attribute__((__ext_vector_type__(3)));
typedef double swift_double4 __attribute__((__ext_vector_type__(4)));
typedef int swift_int2 __attribute__((__ext_vector_type__(2)));
typedef int swift_int3 __attribute__((__ext_vector_type__(3)));
typedef int swift_int4 __attribute__((__ext_vector_type__(4)));
typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2)));
typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3)));
typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4)));
#if !defined(SWIFT_PASTE)
# define SWIFT_PASTE_HELPER(x, y) x##y
#if !defined(SWIFT_METATYPE)
# define SWIFT_METATYPE(X) Class
# if __has_feature(objc_class_property)
# else
# endif
#if __has_attribute(objc_runtime_name)
# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X)))
#if __has_attribute(swift_name)
# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X)))
#if __has_attribute(objc_method_family)
# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X)))
#if __has_attribute(noescape)
# define SWIFT_NOESCAPE __attribute__((noescape))
#if __has_attribute(warn_unused_result)
# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#if __has_attribute(noreturn)
# define SWIFT_NORETURN __attribute__((noreturn))
#if !defined(SWIFT_CLASS_EXTRA)
#if !defined(SWIFT_ENUM_EXTRA)
#if !defined(SWIFT_CLASS)
# if __has_attribute(objc_subclassing_restricted)
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA
# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
# else
# endif
#if !defined(SWIFT_PROTOCOL)
#if !defined(SWIFT_EXTENSION)
# if __has_attribute(objc_designated_initializer)
# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
# else
# endif
#if !defined(SWIFT_ENUM_ATTR)
# if defined(__has_attribute) && __has_attribute(enum_extensibility)
# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility)))
# else
# define SWIFT_ENUM_ATTR(_extensibility)
# endif
#if !defined(SWIFT_ENUM)
# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type
# if __has_feature(generalized_swift_name)
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type
# else
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility)
# endif
# define SWIFT_UNAVAILABLE __attribute__((unavailable))
# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg)))
# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__)))
#if !defined(SWIFT_DEPRECATED)
# define SWIFT_DEPRECATED __attribute__((deprecated))
# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__)))
#if __has_feature(attribute_diagnose_if_objc)
# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning")))
#if __has_feature(modules)
@import Foundation;
@import ObjectiveC;
#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch"
#pragma clang diagnostic ignored "-Wduplicate-method-arg"
#if __has_warning("-Wpragma-clang-attribute")
# pragma clang diagnostic ignored "-Wpragma-clang-attribute"
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wnullability"
#if __has_attribute(external_source_symbol)
# pragma push_macro("any")
# undef any
# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="NoMAD_ADAuth",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol))
# pragma pop_macro("any")
/// A general purpose class that is the main entrypoint for interactions with Active Directory.
@interface NoMADSession : NSObject
- (nonnull instancetype)init SWIFT_UNAVAILABLE;
+ (nonnull instancetype)new SWIFT_DEPRECATED_MSG("-init is unavailable");
#if __has_attribute(external_source_symbol)
# pragma clang attribute pop
#pragma clang diagnostic pop
// NoMAD_ADAuth.h
// NoMAD-ADAuth
// Created by Joel Rennich on 11/4/17.
// Copyright © 2018 Joel Rennich. All rights reserved.
#import <Cocoa/Cocoa.h>
//! Project version number for NoMAD_ADAuth.
FOUNDATION_EXPORT double NoMAD_ADAuthVersionNumber;
//! Project version string for NoMAD_ADAuth.
FOUNDATION_EXPORT const unsigned char NoMAD_ADAuthVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <NoMAD_ADAuth/PublicHeader.h>
framework module NoMAD_ADAuth {
umbrella header "NoMAD_ADAuth.h"
export *
module * { export * }
module NoMAD_ADAuth.Swift {
header "NoMAD_ADAuth-Swift.h"
requires objc
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "">
<plist version="1.0">
<string>Copyright © 2018 Orchard &amp; Grove. All rights reserved.</string>
......@@ -30,7 +30,7 @@ class EULAUI : NSWindowController {
override func windowDidLoad() {
os_log("Calling super.windowDidLoad", log: uiLog, type: .debug)
os_log("Calling super.windowDidLoad", log: uiLog, type: .default)
let scrollNotification = NSNotification.Name.init(rawValue: "NSScrollViewDidLiveScroll")
......@@ -47,17 +47,17 @@ class EULAUI : NSWindowController {
// set the text
if let titleTextPref = getManagedPreference(key: .EULATitle) as? String {
os_log("Setting title text", log: eulaLog, type: .debug )
os_log("Setting title text", log: eulaLog, type: .default )
titleText.stringValue = titleTextPref
if let subTitleTextPref = getManagedPreference(key: .EULASubTitle) as? String {
os_log("Setting subtitle text", log: eulaLog, type: .debug )
os_log("Setting subtitle text", log: eulaLog, type: .default )
subTitleText.stringValue = subTitleTextPref
if let text = getManagedPreference(key: .EULAText) as? String {
os_log("Setting eula text", log: eulaLog, type: .debug )
os_log("Setting eula text", log: eulaLog, type: .default )
// We may need to do some line break things here
textView.string = text.replacingOccurrences(of: "***", with: "\n")
......@@ -67,10 +67,10 @@ class EULAUI : NSWindowController {
completeLogin(authResult: .allow)
os_log("Configure EULA window", log: eulaLog, type: .debug)
os_log("Configure EULA window", log: eulaLog, type: .default)
os_log("create background windows", log: eulaLog, type: .debug)
os_log("create background windows", log: eulaLog, type: .default)
......@@ -173,7 +173,7 @@ class EULAUI : NSWindowController {
/// - Parameter authResult:`Authorizationresult` enum value that indicates if login should proceed.
fileprivate func completeLogin(authResult: AuthorizationResult) {
os_log("Complete login process", log: uiLog, type: .debug)
os_log("Complete login process", log: uiLog, type: .default)
let error = mech?.fPlugin.pointee.fCallbacks.pointee.SetResult((mech?.fEngine)!, authResult)
if error != noErr {
os_log("Got error setting authentication result", log: uiLog, type: .error)
......@@ -183,7 +183,7 @@ class EULAUI : NSWindowController {
fileprivate func loginApperance() {
os_log("Setting window level", log: uiLog, type: .debug)
os_log("Setting window level", log: uiLog, type: .default)
self.window?.level = .screenSaver
self.window?.titlebarAppearsTransparent = true
......@@ -196,7 +196,7 @@ class EULAUI : NSWindowController {
var image: NSImage?
// Is a background image path set? If not just use gray.
if let backgroundImage = getManagedPreference(key: .BackgroundImage) as? String {
os_log("BackgroundImage preferences found.", log: uiLog, type: .debug)
os_log("BackgroundImage preferences found.", log: uiLog, type: .default)
image = NSImage(contentsOf: URL(fileURLWithPath: backgroundImage))
for screen in NSScreen.screens {
<?xml version="1.0" encoding="UTF-8"?>
<document type="" version="3.0" toolsVersion="14113" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="" version="3.0" toolsVersion="14460.31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<deployment identifier="macosx"/>
<plugIn identifier="" version="14113"/>
<plugIn identifier="" version="14460.31"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
<capability name="system font weights other than Regular or Bold" minToolsVersion="7.0"/>
<customObject id="-2" userLabel="File's Owner" customClass="EULAUI" customModule="NoMADLoginAD" customModuleProvider="target">
......@@ -22,10 +21,10 @@
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" animationBehavior="default" id="QvC-M9-y7g">
<window allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g">
<windowStyleMask key="styleMask" titled="YES"/>
<rect key="contentRect" x="196" y="240" width="706" height="449"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="706" height="449"/>
<autoresizingMask key="autoresizingMask"/>
......@@ -33,14 +32,15 @@
<scrollView fixedFrame="YES" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rhH-jO-XbW">
<rect key="frame" x="20" y="48" width="666" height="327"/>
<autoresizingMask key="autoresizingMask"/>
<clipView key="contentView" ambiguous="YES" id="C09-Oc-zUj">
<clipView key="contentView" ambiguous="YES" drawsBackground="NO" id="C09-Oc-zUj">
<rect key="frame" x="1" y="1" width="664" height="325"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<textView ambiguous="YES" editable="NO" selectable="NO" importsGraphics="NO" verticallyResizable="YES" baseWritingDirection="leftToRight" usesFontPanel="YES" findStyle="panel" continuousSpellChecking="YES" allowsCharacterPickerTouchBarItem="NO" usesRuler="YES" allowsNonContiguousLayout="YES" quoteSubstitution="YES" dashSubstitution="YES" textCompletion="NO" spellingCorrection="YES" smartInsertDelete="YES" id="W9R-pJ-Y3v">
<rect key="frame" x="0.0" y="0.0" width="664" height="336"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
<size key="minSize" width="664" height="325"/>
<size key="maxSize" width="671" height="10000000"/>
<attributedString key="textStorage">
......@@ -51,6 +51,7 @@ Aenean orci tellus, rutrum ut vulputate eu, efficitur et lorem. Mauris sodales i
Proin odio elit, sollicitudin lacinia iaculis vel, pellentesque sed elit. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque finibus libero lorem, et blandit dolor porta at. Nulla ullamcorper ut enim at pulvinar. Vestibulum consequat, ex at aliquam laoreet, ante nisi vestibulum urna, in varius purus justo a libero. Cras sed felis iaculis, sodales mi at, venenatis enim. Donec nunc neque, elementum a viverra eget, vehicula et elit. Mauris euismod est mattis nulla sodales, et faucibus magna sollicitudin. Vestibulum non erat a urna ornare aliquet. Donec dapibus scelerisque nibh nec fringilla. Curabitur ultrices ligula sit amet neque varius, sit amet sagittis velit facilisis. Integer et dui a magna euismod elementum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</mutableString>
<color key="NSColor" name="textColor" catalog="System" colorSpace="catalog"/>
<font key="NSFont" size="12" name="Helvetica"/>
<real key="NSKern" value="0.0"/>
<paragraphStyle key="NSParagraphStyle" alignment="justified" lineBreakMode="wordWrapping" baseWritingDirection="leftToRight" defaultTabInterval="36" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO">
......@@ -59,10 +60,9 @@ Proin odio elit, sollicitudin lacinia iaculis vel, pellentesque sed elit. Orci v
<color key="insertionPointColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<color key="insertionPointColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="YES" id="P9H-8W-Hem">
<rect key="frame" x="-100" y="-100" width="87" height="18"/>
......@@ -86,6 +86,10 @@ class CreateUser: NoLoMechanism {
} else {
// no user to create
os_log("Skipping local account creation", log: createUserLog, type: .default)
// Set the login timestamp if requested
setTimestampFor(nomadUser as? String ?? "")
os_log("Account creation skipped, allowing login", log: createUserLog, type: .debug)
let _ = allowLogin()
......@@ -121,7 +125,7 @@ class CreateUser: NoLoMechanism {
let picData = NSData(contentsOf: picURL)
let picString = picData?.description ?? ""
let attrs: [AnyHashable:Any] = [
var attrs: [AnyHashable:Any] = [
kODAttributeTypeFullName: [first + " " + last],
kODAttributeTypeNFSHomeDirectory: [ "/Users/" + shortName ],
kODAttributeTypeUserShell: ["/bin/bash"],
......@@ -129,9 +133,18 @@ class CreateUser: NoLoMechanism {
kODAttributeTypePrimaryGroupID: [gid],
kODAttributeTypeAuthenticationHint: [""],
kODAttributeTypePicture: [userPicture],
kODAttributeTypeJPEGPhoto: [picString]
kODAttributeTypeJPEGPhoto: [picString],
kODAttributeADUser: [getHint(type: .kerberos_principal) as? String ?? ""]
if getManagedPreference(key: .UseCNForFullName) as? Bool ?? false {
attrs[kODAttributeTypeFullName] = [getHint(type: .noMADFull) as? String ?? ""]