0000-12-31 18:09:24 -05:50
# Authors: Simo Sorce <ssorce@redhat.com>
#
# Copyright (C) 2007 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
2008-02-04 14:15:52 -06:00
# published by the Free Software Foundation; version 2 only
0000-12-31 18:09:24 -05:50
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
import logging
import socket
import errno
import getpass
0000-12-31 18:09:24 -05:50
import os
import re
import fileinput
import sys
2008-03-03 15:10:06 -06:00
import struct
2008-03-27 14:33:06 -05:00
import fcntl
2007-12-18 12:03:34 -06:00
2009-02-05 14:03:08 -06:00
from ipapython import ipautil
from ipapython import dnsclient
0000-12-31 18:09:24 -05:50
def get_fqdn ( ) :
fqdn = " "
try :
fqdn = socket . getfqdn ( )
except :
try :
fqdn = socket . gethostname ( )
except :
fqdn = " "
return fqdn
2008-03-06 12:17:28 -06:00
2008-09-16 21:18:11 -05:00
def verify_fqdn ( host_name , no_host_dns = False ) :
2008-03-30 19:00:43 -05:00
0000-12-31 18:09:24 -05:50
if len ( host_name . split ( " . " ) ) < 2 or host_name == " localhost.localdomain " :
raise RuntimeError ( " Invalid hostname: " + host_name )
2008-03-30 19:00:43 -05:00
try :
hostaddr = socket . getaddrinfo ( host_name , None )
except :
raise RuntimeError ( " Unable to resolve host name, check /etc/hosts or DNS name resolution " )
if len ( hostaddr ) == 0 :
raise RuntimeError ( " Unable to resolve host name, check /etc/hosts or DNS name resolution " )
for a in hostaddr :
if a [ 4 ] [ 0 ] == ' 127.0.0.1 ' or a [ 4 ] [ 0 ] == ' ::1 ' :
2008-05-08 16:13:15 -05:00
raise RuntimeError ( " The IPA Server hostname cannot resolve to localhost ( %s ). A routable IP address must be used. Check /etc/hosts to see if %s is an alias for %s " % ( a [ 4 ] [ 0 ] , host_name , a [ 4 ] [ 0 ] ) )
2008-03-30 19:00:43 -05:00
try :
revname = socket . gethostbyaddr ( a [ 4 ] [ 0 ] ) [ 0 ]
except :
raise RuntimeError ( " Unable to resolve the reverse ip address, check /etc/hosts or DNS name resolution " )
if revname != host_name :
raise RuntimeError ( " The host name %s does not match the reverse lookup %s " % ( host_name , revname ) )
2008-09-16 21:18:11 -05:00
if no_host_dns :
print " Warning: skipping DNS resolution of host " , host_name
return
2008-03-30 19:00:43 -05:00
# Verify this is NOT a CNAME
rs = dnsclient . query ( host_name + " . " , dnsclient . DNS_C_IN , dnsclient . DNS_T_CNAME )
if len ( rs ) != 0 :
for rsn in rs :
if rsn . dns_type == dnsclient . DNS_T_CNAME :
raise RuntimeError ( " The IPA Server Hostname cannot be a CNAME, only A names are allowed. " )
2008-03-03 15:10:06 -06:00
# Verify that it is a DNS A record
rs = dnsclient . query ( host_name + " . " , dnsclient . DNS_C_IN , dnsclient . DNS_T_A )
if len ( rs ) == 0 :
2008-03-30 19:00:43 -05:00
print " Warning: Hostname ( %s ) not found in DNS " % host_name
return
rec = None
for rsn in rs :
if rsn . dns_type == dnsclient . DNS_T_A :
rec = rsn
break
if rec == None :
print " Warning: Hostname ( %s ) not found in DNS " % host_name
return
2008-03-03 15:10:06 -06:00
# Compare the forward and reverse
2008-03-30 19:00:43 -05:00
forward = rec . dns_name
2008-03-03 15:10:06 -06:00
2008-03-30 19:00:43 -05:00
addr = socket . inet_ntoa ( struct . pack ( ' <L ' , rec . rdata . address ) )
ipaddr = socket . inet_ntoa ( struct . pack ( ' !L ' , rec . rdata . address ) )
2008-03-03 15:10:06 -06:00
2008-03-30 19:00:43 -05:00
addr = addr + " .in-addr.arpa. "
2008-03-03 15:10:06 -06:00
rs = dnsclient . query ( addr , dnsclient . DNS_C_IN , dnsclient . DNS_T_PTR )
if len ( rs ) == 0 :
2008-03-30 19:00:43 -05:00
raise RuntimeError ( " Cannot find Reverse Address for %s ( %s ) " % ( host_name , addr ) )
2008-03-03 15:10:06 -06:00
2008-03-30 19:00:43 -05:00
rev = None
for rsn in rs :
if rsn . dns_type == dnsclient . DNS_T_PTR :
rev = rsn
break
2008-03-03 15:10:06 -06:00
2008-03-30 19:00:43 -05:00
if rev == None :
raise RuntimeError ( " Cannot find Reverse Address for %s ( %s ) " % ( host_name , addr ) )
2008-03-06 12:17:28 -06:00
2008-03-30 19:00:43 -05:00
reverse = rev . rdata . ptrdname
if forward != reverse :
raise RuntimeError ( " The DNS forward record %s does not match the reverse address %s " % ( forward , reverse ) )
2008-03-06 12:17:28 -06:00
2009-11-23 02:15:35 -06:00
def verify_ip_address ( ip ) :
is_ok = True
try :
socket . inet_pton ( socket . AF_INET , ip )
except :
try :
socket . inet_pton ( socket . AF_INET6 , ip )
except :
print " Unable to verify IP address "
is_ok = False
return is_ok
def read_ip_address ( host_name , fstore ) :
while True :
ip = ipautil . user_input ( " Please provide the IP address to be used for this host name " , allow_empty = False )
if ip == " 127.0.0.1 " or ip == " ::1 " :
print " The IPA Server can ' t use localhost as a valid IP "
continue
if verify_ip_address ( ip ) :
break
print " Adding [ " + ip + " " + host_name + " ] to your /etc/hosts file "
fstore . backup_file ( " /etc/hosts " )
hosts_fd = open ( ' /etc/hosts ' , ' r+ ' )
hosts_fd . seek ( 0 , 2 )
hosts_fd . write ( ip + ' \t ' + host_name + ' ' + host_name . split ( ' . ' ) [ 0 ] + ' \n ' )
hosts_fd . close ( )
return ip
def read_dns_forwarders ( ) :
addrs = [ ]
2010-02-08 12:31:57 -06:00
if ipautil . user_input ( " Do you wish to configure DNS forwarders? " , False ) :
print " Please enter the IP addresses of DNS forwarders that you want to use. "
print " After you are done, enter a blank line to stop. "
while True :
ip = ipautil . user_input ( " Enter IP address for a DNS forwarder " ,
allow_empty = True )
if not ip :
break
if ip == " 127.0.0.1 " or ip == " ::1 " :
print " You cannot use localhost as a DNS forwarder "
continue
if not verify_ip_address ( ip ) :
continue
print " DNS forwarder %s added " % ip
addrs . append ( ip )
2009-11-23 02:15:35 -06:00
if not addrs :
print " No DNS forwarders configured "
return addrs
0000-12-31 18:09:24 -05:50
def port_available ( port ) :
""" Try to bind to a port on the wildcard host
Return 1 if the port is available
Return 0 if the port is in use
"""
rv = 1
try :
s = socket . socket ( socket . AF_INET , socket . SOCK_STREAM )
2008-03-27 14:33:06 -05:00
fcntl . fcntl ( s , fcntl . F_SETFD , fcntl . FD_CLOEXEC )
0000-12-31 18:09:24 -05:50
s . bind ( ( ' ' , port ) )
s . close ( )
except socket . error , e :
if e [ 0 ] == errno . EADDRINUSE :
rv = 0
if rv :
try :
s = socket . socket ( socket . AF_INET6 , socket . SOCK_STREAM )
2008-03-27 14:33:06 -05:00
fcntl . fcntl ( s , fcntl . F_SETFD , fcntl . FD_CLOEXEC )
0000-12-31 18:09:24 -05:50
s . bind ( ( ' ' , port ) )
s . close ( )
except socket . error , e :
if e [ 0 ] == errno . EADDRINUSE :
rv = 0
return rv
2009-11-23 02:18:25 -06:00
def standard_logging_setup ( log_filename , debug = False , filemode = ' w ' ) :
2008-05-20 03:19:19 -05:00
old_umask = os . umask ( 077 )
0000-12-31 18:09:24 -05:50
# Always log everything (i.e., DEBUG) to the log
# file.
logging . basicConfig ( level = logging . DEBUG ,
format = ' %(asctime)s %(levelname)s %(message)s ' ,
filename = log_filename ,
2009-11-23 02:18:25 -06:00
filemode = filemode )
2008-05-20 03:19:19 -05:00
os . umask ( old_umask )
0000-12-31 18:09:24 -05:50
console = logging . StreamHandler ( )
# If the debug option is set, also log debug messages to the console
if debug :
console . setLevel ( logging . DEBUG )
else :
# Otherwise, log critical and error messages
console . setLevel ( logging . ERROR )
formatter = logging . Formatter ( ' %(name)-12s : %(levelname)-8s %(message)s ' )
console . setFormatter ( formatter )
logging . getLogger ( ' ' ) . addHandler ( console )
2008-09-12 19:34:25 -05:00
def get_password ( prompt ) :
if os . isatty ( sys . stdin . fileno ( ) ) :
return getpass . getpass ( prompt )
else :
return sys . stdin . readline ( ) . rstrip ( )
2008-04-29 13:12:00 -05:00
def read_password ( user , confirm = True , validate = True ) :
0000-12-31 18:09:24 -05:50
correct = False
pwd = " "
while not correct :
2008-09-12 19:34:25 -05:00
pwd = get_password ( user + " password: " )
0000-12-31 18:09:24 -05:50
if not pwd :
continue
2008-04-29 13:12:00 -05:00
if validate and len ( pwd ) < 8 :
0000-12-31 18:09:24 -05:50
print " Password must be at least 8 characters long "
continue
2008-04-29 13:12:00 -05:00
if not confirm :
correct = True
continue
2008-09-12 19:34:25 -05:00
pwd_confirm = get_password ( " Password (confirm): " )
0000-12-31 18:09:24 -05:50
if pwd != pwd_confirm :
print " Password mismatch! "
print " "
else :
correct = True
print " "
return pwd
0000-12-31 18:09:24 -05:50
def update_file ( filename , orig , subst ) :
if os . path . exists ( filename ) :
pattern = " %s " % re . escape ( orig )
p = re . compile ( pattern )
for line in fileinput . input ( filename , inplace = 1 ) :
if not p . search ( line ) :
sys . stdout . write ( line )
else :
sys . stdout . write ( p . sub ( subst , line ) )
fileinput . close ( )
return 0
else :
print " File %s doesn ' t exist. " % filename
return 1
2009-04-17 16:17:31 -05:00
def set_directive ( filename , directive , value , quotes = True , separator = ' ' ) :
2008-07-11 10:34:29 -05:00
""" Set a name/value pair directive in a configuration file.
This has only been tested with nss . conf
"""
2009-04-17 16:17:31 -05:00
valueset = False
2008-07-11 10:34:29 -05:00
fd = open ( filename )
2009-08-11 16:08:09 -05:00
newfile = [ ]
2008-07-11 10:34:29 -05:00
for line in fd :
if directive in line :
2009-04-17 16:17:31 -05:00
valueset = True
if quotes :
2009-08-11 16:08:09 -05:00
newfile . append ( ' %s %s " %s " \n ' % ( directive , separator , value ) )
2009-04-17 16:17:31 -05:00
else :
2009-08-11 16:08:09 -05:00
newfile . append ( ' %s %s %s \n ' % ( directive , separator , value ) )
2008-07-11 10:34:29 -05:00
else :
2009-08-11 16:08:09 -05:00
newfile . append ( line )
2008-07-11 10:34:29 -05:00
fd . close ( )
2009-04-17 16:17:31 -05:00
if not valueset :
if quotes :
2009-08-11 16:08:09 -05:00
newfile . append ( ' %s %s " %s " \n ' % ( directive , separator , value ) )
2009-04-17 16:17:31 -05:00
else :
2009-08-11 16:08:09 -05:00
newfile . append ( ' %s %s %s \n ' % ( directive , separator , value ) )
2008-07-11 10:34:29 -05:00
fd = open ( filename , " w " )
2009-08-11 16:08:09 -05:00
fd . write ( " " . join ( newfile ) )
2008-07-11 10:34:29 -05:00
fd . close ( )
2009-08-11 16:08:09 -05:00
def get_directive ( filename , directive , separator = ' ' ) :
2009-04-17 16:17:31 -05:00
"""
A rather inefficient way to get a configuration directive .
"""
fd = open ( filename , " r " )
for line in fd :
if directive in line :
line = line . strip ( )
result = line . split ( separator , 1 ) [ 1 ]
result = result . strip ( ' " ' )
fd . close ( )
return result
fd . close ( )
return None
2007-12-18 12:03:34 -06:00
def kadmin ( command ) :
0000-12-31 18:09:24 -05:50
ipautil . run ( [ " /usr/kerberos/sbin/kadmin.local " , " -q " , command ] )
2007-12-18 12:03:34 -06:00
def kadmin_addprinc ( principal ) :
kadmin ( " addprinc -randkey " + principal )
def kadmin_modprinc ( principal , options ) :
kadmin ( " modprinc " + options + " " + principal )
def create_keytab ( path , principal ) :
try :
if ipautil . file_exists ( path ) :
os . remove ( path )
except os . error :
logging . critical ( " Failed to remove %s . " % path )
kadmin ( " ktadd -k " + path + " " + principal )
0000-12-31 18:09:24 -05:50