Openconnect on Mac for Cisco and Fortinet

Openconnect as a replacement for Cisco AnyConnect is amazing. I had to use a Fortinet VPN concentrator and noticed that Openconnect added support for it in March of 2021. Here are the brew commands I used to install the version that had that support.

brew install autoconf automake
brew install openconnect -s --head
You can see fortinet in the protocol options

Macintosh Logon Scripts

Here is a set of Mac logon scripts I wrote for a Windows/AD environment. There are a set of plist files that launch perl scripts and different stages. The logon scripts are local and self-update from the sysvol directory.

edu.fitsuny.mac_logon_init.plist





	Label
	edu.fitsuny.edu.mac_system_logon
	ProgramArguments
	
		/etc/etsscripts/mac_logon_init.pl
	
	RunAtLoad
	


edu.fitsuny.mac_user_logon.plist





	Label
	edu.fitsuny.mac_user_logon
	ProgramArguments
	
		/etc/etsscripts/mac_user_logon.pl
	
	RunAtLoad
	


mac_system_logon.pl

#!/usr/bin/perl -l
#Please make your function a sub and then call it.
#FYI: an error here will break the entire script
open (LOG, '>>/tmp/logon_system.txt');
print LOG "Running System Hook V1.0 \n";

#remember with admitmac the username might be @fitsuny.edu
$username = $ARGV[0];


#updates the loader.pl just in case we make changes there.
updateloader();

sub updateloader
{
	system('smbclient //fit-c108-01/netlogon Password -U mac_logon -c \'get \\Macintosh\\installer\\mac_logon_init.pl /etc/etsscripts/mac_logon_init.pl\'');
	if ($? != 0)
	{ #try dc 1
		system('smbclient //fit-c108-02/netlogon Password -U mac_logon -c \'get \\Macintosh\\installer\\mac_logon_init.pl /etc/etsscripts/mac_logon_init.pl\'');
	if ($? != 0)
	{# failed again print error
		print LOG 'SYSTEM: Cannot download loader.pl script\n';
	}

	chmod(0755,'/etc/etsscripts/mac_logon_init.pl');
}
}
#!/usr/bin/perl -l
#Please make your process a sub and then call it.
#FYI: an error here will break the entire script
#This runs at user the user profie is in ~/ || mkdir() does not understand ~/
#
open (LOG, '>/tmp/logon_user.txt');
print LOG "Running User Hook V1.0 \n";

#remember with admitmac the username might be @fitsuny.edu

my $username = $ENV{'USER'};
my $profiledir = $ENV{'HOME'};

if ( $username =~ m/[@]/ )
{
	my @tmpusername = split(/@/,$username);
        $username = $tmpusername[0];
}
print LOG "USER: username " . $username . "\n";

#system test script, an example of giving the user a GUI popup box from a perl script
#system('osascript -l AppleScript -e \'tell Application "Finder" to display dialog "Call Frank"\'');

#get Prirole once
$usertype = get_prirole();
print LOG "USER: using prirole " . $usertype . "\n";

disable_dsstore();
mount_winfs();
#emgmesg();

#their profile is in Users which means they are not using admit mac
if ($profiledir =~ m/\/Users\//)
{
	mount_stanNDrive();	
}



sub disable_dsstore
{
	#this will disable .DS_STORE on network volumes
	#This will stop some weird bugs

	system('defaults write com.apple.desktopservices DSDontWriteNetworkStores true');
}

sub mount_stanNDrive
{
	use Net::LDAP;

	$ldap = Net::LDAP->new ('fit-c108-01') or die "$@";
	$ad = $ldap->bind('cn=ldapsearch,ou=fitusers,dc=fitsuny,dc=edu', password => 'password);
	$ad = $ldap->search (base => 'ou=FitUsers,dc=fitsuny,dc=edu',
        	                filter => "(&(cn=" . $username . "))",
        	                attrs => ['homeDirectory'],
        	                );

	$ad->code && die $ad->error;


	$winHomeDir =  $ad->entry->get_value('homeDirectory');
	$ad = $ldap->unbind;

	$winHomeDir =~ s/\\\\/smb:\/\//;
	$winHomeDir =~ s/\\/\//g;

	$osascript = qq[mount volume "$winHomeDir"];
	system( "osascript -e '$osascript'");

}
sub mount_winfs
{
	#check to make sure mount exists
	#check pri-role to see what server they are on

	my $pilot_user  = shift;

	my $servershare;
	$servershare = 'fs-c108-03/student_home$/'  if ifmember($username,'students') ;
	$servershare = 'fs-c108-04/faculty_home$/'  if ifmember($username,'faculty')  ;

	return unless $servershare; # Don't attempt mount if no Y: drive for user

	my $winfs_path = '//' . $servershare . $username;
	$mntfolder = $ENV{'HOME'} . '/Desktop/' . $username . '_CAMPUSFILES';

	print LOG $servershare . "\n";
	print LOG $mntfolder . "\n";
	system('mkdir ' . $mntfolder);
    	system('mount_smbfs -o nobrowse ' . $winfs_path . ' ' . $mntfolder);

	#get list of mounts
	$mountlist = `mount`;
	if ($mountlist =~ m/CAMPUSFILES/ix) 
	{# Successful mount
	} 
	else 
	{# Match attempt failed
		system('rm -dfr ' . $mntfolder);
	}

}

sub get_prirole
{
	my $ldapsearch = qq[ldapsearch -h ldap.fitsuny.edu -b "dc=fitsuny,dc=edu" -LLL -x "(uid=$username)" fitprirole];
	my $usertype = `$ldapsearch`;

	$usertype =~ s/^.*fitprirole:\s+(.*)$/$1/s;

	return $usertype;
}

sub ifmember
{
#does not do nested groups.

	$_username = shift;
	$_group = shift;
	use Net::LDAP;
	$ldap = Net::LDAP->new ('fit-c108-01') or die "$@";
	$ad = $ldap->bind('cn=ldapsearch,ou=fitusers,dc=fitsuny,dc=edu', password => 'password');
	$ad = $ldap->search (base =>'ou=FiTUsers,dc=fitsuny,dc=edu',
				filter => "(&(cn=" . $_username . ")(memberof=cn=" . $_group . ",ou=fitgroups,dc=fitsuny,dc=edu))",
				#attrs => ['memberOf'],
				);
	$ad->code && $ad->error;

	return $ad->count();
				

}


sub emgmesg
{
$message = "LOGIN TO MyFIT TO REGISTER FOR EMERGENCY MESSAGE NOTIFICATIONS
Get timely announcements in the event of a campus emergency or a weather-related closure of the college via text message, email, or voicemail.

Would you like to sign up now?";

#icons Types (stop, note, caution)
$icon = 'note';

#button types (ok, yesno)
$buttons = 'yesno';

#action
$action = 'http://myfit.fitnyc.edu';

if($icon eq 'stop')
	{
		$ic = '0';
	}
	elsif($icon eq 'note')
	{
		$ic = '1';
	}
	elsif($icon eq 'caution')
	{
		$ic = '2';
	}

	if($buttons eq 'ok')
	{
		$bu = '{"OK"}';
	}
	elsif($buttons eq 'yesno')
	{
		$bu = '{"YES","NO"}';
	}

	#mac way
	$result = `/usr/bin/osascript <<-EOF

    tell application "System Events"
        activate
        display dialog "$message" buttons $bu with icon $ic
    end tell

EOF`;

chomp($result);
if (($buttons eq 'yesno') && ($result eq 'button returned:YES'))
{
	system('open ' . $action);
}
}

stunnel on mac

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<plist version="1.0">

<dict>

        <key>Label</key>

        <string>org.stunnel.startup</string>

        <key>ProgramArguments</key>

        <array>

                <string>/opt/local/bin/stunnel</string>

        </array>

        <key>RunAtLoad</key>

        <true/>

</dict>

</plist>

I needed to have the macports version of stunnel run on startup.

Here is my config that i put into /Library/LaunchDaemons and named it org.stunnel.startup.plist