diff --git a/CMakeLists.txt b/CMakeLists.txt index c6ef08e..07f3106 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,7 @@ INCLUDE_DIRECTORIES( add_executable(nwwebui nwwebui.c) add_executable(check_login check_login.c) +add_executable(smart_userlist smart_userlist.c) ################################# # Linking @@ -86,6 +87,11 @@ target_link_libraries(check_login ${DL_LIBRARY} ) +target_link_libraries(smart_userlist + ${PAM_LIBRARY} + ${DL_LIBRARY} +) + ################################# # Install Files ############## @@ -108,12 +114,28 @@ install(FILES static/favicon.ico DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR} install(FILES static/favicon-32x32.png DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static) install(FILES static/favicon-16x16.png DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static) install(FILES static/apple-touch-icon.png DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static) +install(FILES static/icon-start.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static) +install(FILES static/icon-service.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static) +install(FILES static/icon-general.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static) +install(FILES static/icon-dirs.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static) +install(FILES static/icon-configh.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static) +install(FILES static/icon-security.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static) +install(FILES static/icon-susers.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static) +install(FILES static/icon-volumes.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static) +install(FILES static/icon-devices.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static) +install(FILES static/icon-logging.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static) +install(FILES static/icon-smart.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static) +install(FILES static/icon-stations.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static) +install(FILES static/icon-users.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static) +install(FILES static/icon-groups.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static) +install(FILES static/icon-queues.svg DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}/static) if(WITH_SYSTEMD) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/mars-nwe-webui.service DESTINATION ${SYSTEMD_SERVICES_INSTALL_DIR}) endif() install(TARGETS check_login DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}) +install(TARGETS smart_userlist DESTINATION ${MARS_NWE_INSTALL_FULL_LIBEXECDIR}) install(TARGETS nwwebui DESTINATION ${CMAKE_INSTALL_SBINDIR}) diff --git a/apply.pl b/apply.pl index ab32dc5..8590a55 100644 --- a/apply.pl +++ b/apply.pl @@ -22,12 +22,54 @@ # # +sub read_smart_bindery_values() +{ + my( $bind_server, $bind_user, $bind_pass ) = ( '', '', '' ); + + if( open( my $fh, '<' . $smart_nwclient_path ) ) + { + my $line = <$fh>; + close( $fh ); + + chomp( $line ) if defined( $line ); + ( $bind_server, $bind_user, $bind_pass ) = split( '[/ ]', $line ) if defined( $line ); + } + + $bind_server = '' unless defined( $bind_server ); + $bind_user = '' unless defined( $bind_user ); + $bind_pass = '' unless defined( $bind_pass ); + + return( $bind_server, $bind_user, $bind_pass ); +} + +sub write_smart_bindery_values( $$$ ) +{ + my( $bind_server, $bind_user, $bind_pass ) = @_; + + $bind_server = '' unless defined( $bind_server ); + $bind_user = '' unless defined( $bind_user ); + $bind_pass = '' unless defined( $bind_pass ); + + open( my $fh, '>' . $smart_nwclient_path ) or die "Could not open $smart_nwclient_path: $!"; + print( $fh $bind_server . '/' . $bind_user . ' ' . $bind_pass . "\n" ); + close( $fh ); + + chown( scalar( getpwnam( $nonroot_user ) ), 0, $smart_nwclient_path ); + chmod( 0600, $smart_nwclient_path ); +} + + sub handle_request() { if( $c[1] eq 'general' ) { setc( 2, server_name ); setc( 3, internal_net ); + if( defined( $p{sync_smart_bind_server} ) && $p{sync_smart_bind_server} eq 'on' && defined( $p{server_name} ) && $p{server_name} ne '' ) + { + my( $old_bind_server, $old_bind_user, $old_bind_pass ) = read_smart_bindery_values(); + write_smart_bindery_values( $p{server_name}, $old_bind_user, $old_bind_pass ); + } setc( 16, test ); setc( 210, timing_down ); setc( 211, timing_warn ); @@ -109,10 +151,6 @@ sub handle_request() { delconfigline( '4 ' . $c[2] ); } - if( defined( $p{interface_manual} ) && $p{interface_manual} ne '' ) - { - $p{interface} = $p{interface_manual}; - } $p{interface} =~ s/[^-_\.A-Za-z0-9:\*]//g; if( $p{number} ne '' ) { @@ -148,12 +186,13 @@ sub handle_request() close( FILE ); } - open( FILE, '>' . $smart_nwclient_path ) or die "Could not open $smart_nwclient_path: $!"; - print( FILE $p{bind_server} . '/' . $p{bind_user} . ' ' . $p{bind_pass } . "\n" ); - close( FILE ); - - chown( scalar( getpwnam( $nonroot_user ) ), 0, $smart_nwclient_path ); - chmod( 0600, $smart_nwclient_path ); + write_smart_bindery_values( $p{bind_server}, $p{bind_user}, $p{bind_pass} ); + + if( defined( $p{sync_general_server_name} ) && $p{sync_general_server_name} eq 'on' && defined( $p{bind_server} ) && $p{bind_server} ne '' ) + { + $p{server_name} = $p{bind_server}; + setc( 2, server_name ); + } } elsif( $c[1] eq 'users' ) { @@ -355,6 +394,92 @@ EOF redirect( '/settings/queues' ); } + + elsif( $c[1] eq 'advanced' ) + { + my $advanced_category = $p{advanced_category}; + $advanced_category = 'all' if ! defined( $advanced_category ) || $advanced_category eq ''; + + my $save_devices = ( $advanced_category eq 'all' || $advanced_category eq 'devices' ); + my $save_security = ( $advanced_category eq 'all' || $advanced_category eq 'security' ); + my $save_users = ( $advanced_category eq 'all' || $advanced_category eq 'users' ); + my $save_queues = ( $advanced_category eq 'all' || $advanced_category eq 'queues' ); + my $save_configh = ( $advanced_category eq 'all' || $advanced_category eq 'configh' ); + my $save_stations = ( $advanced_category eq 'all' || $advanced_category eq 'stations' ); + my $save_network = ( $advanced_category eq 'all' || $advanced_category eq 'network' ); + + if( $save_devices ) + { + my $device_flags = 0; + $device_flags += 1 if $p{dev_keep} eq 'on'; + $device_flags += 2 if $p{dev_auto} eq 'on'; + $device_flags += 4 if $p{dev_remove_all} eq 'on'; + + delconfigline( 5 ); + addconfigline( '5 ' . $device_flags ) if $device_flags != 0; + } + + if( $save_security ) + { + my $security_flags = 0; + $security_flags += 0x8 if $p{sec_supervisor_ignore} eq 'on'; + $security_flags += 0x40 if $p{sec_2gb_free} eq 'on'; + $security_flags += 0x200 if $p{sec_int17} eq 'on'; + $security_flags += 0x2 if $p{sec_delete_open} eq 'on'; + $security_flags += 0x4 if $p{sec_rename_open} eq 'on'; + + delconfigline( 8 ); + addconfigline( '8 ' . $security_flags ) if $security_flags != 0; + } + + if( $save_users ) + { + my $bindery_flags = 0; + $bindery_flags += 1 if $p{bindery_empty_scripts} eq 'on'; + + delconfigline( 17 ); + addconfigline( '17 ' . $bindery_flags ) if $bindery_flags != 0; + } + + if( $save_queues ) + { + my $queue_flags = 0; + $queue_flags += 1 if $p{queue_no_banner} eq 'on'; + + delconfigline( 18 ); + addconfigline( '18 ' . $queue_flags ) if $queue_flags != 0; + + delconfigline( 22 ); + foreach my $line ( split( /\r?\n/, $p{print_servers} ) ) + { + $line =~ s/^\s+//; + $line =~ s/\s+$//; + next if $line eq ''; + $line =~ s/#.*//; + next if $line eq ''; + addconfigline( '22 ' . $line ); + } + } + + if( $save_configh ) + { + setc( 50, conversion_tables ); + setc( 80, max_dir_search_handles ); + } + + if( $save_network ) + { + setc( 310, watchdogs ); + } + + if( $save_stations ) + { + setc( 400, station_file ); + setc( 401, nearest_replies ); + setc( 402, connect_replies ); + } + } + else { putp(); @@ -365,6 +490,42 @@ EOF writeconfig(); } + +sub add_mask_flag( $$$ ) +{ + my( $value, $param, $mask ) = @_; + if( defined( $p{$param} ) && $p{$param} ne '' ) + { + $value |= $mask; + } + return $value; +} + +sub addconfig_hex( $$ ) +{ + delconfigline( $_[0] ); + addconfigline( $_[0] . ' 0x' . sprintf( '%x', $_[1] ) ); +} + +sub sanitize_simple_value( $ ) +{ + my $v = $_[0]; + $v = '' unless defined $v; + $v =~ s/[\r\n]//g; + $v =~ s/^\s+//; + $v =~ s/\s+$//; + $v =~ s/[^-_\.\/\:\~A-Za-z0-9]//g; + return $v; +} + +sub sanitize_number_value( $ ) +{ + my $v = $_[0]; + $v = '' unless defined $v; + $v =~ s/[^0-9xXa-fA-F\-]//g; + return $v; +} + sub putp() { $cc =~ s/.*\?//; diff --git a/settings.pl b/settings.pl index efc1d2c..4cc511c 100644 --- a/settings.pl +++ b/settings.pl @@ -51,6 +51,112 @@ sub delete_confirm_attr( $ ) return ' onclick="return confirm(\'Delete ' . $what . '?\')"'; } +sub advanced_link_row( $$ ) +{ + my( $href, $label ) = @_; + + return qq|\t\n\t\t$label\n\t\n|; +} + +sub advanced_category() +{ + my $cat = $c[2]; + + $cat = 'all' if ! defined( $cat ) || $cat eq ''; + + if( $cat =~ /^(devices|security|users|queues|configh|stations|network|all)$/ ) + { + return $cat; + } + + return 'all'; +} + +sub advanced_section_visible( $$ ) +{ + my( $cat, $section ) = @_; + + return 1 if $cat eq 'all'; + + return 1 if $cat eq 'devices' && $section =~ /^(5)$/; + return 1 if $cat eq 'security' && $section =~ /^(8)$/; + return 1 if $cat eq 'users' && $section =~ /^(17)$/; + return 1 if $cat eq 'queues' && $section =~ /^(18|22)$/; + return 1 if $cat eq 'configh' && $section =~ /^(50|80)$/; + return 1 if $cat eq 'stations' && $section =~ /^(400|401|402)$/; + return 1 if $cat eq 'network' && $section =~ /^(310)$/; + + return 0; +} + +sub advanced_title( $ ) +{ + my $cat = $_[0]; + + return 'Advanced device settings' if $cat eq 'devices'; + return 'Advanced security settings' if $cat eq 'security'; + return 'Advanced user / bindery settings' if $cat eq 'users'; + return 'Advanced print queue settings' if $cat eq 'queues'; + return 'Advanced precompiled / path settings' if $cat eq 'configh'; + return 'Advanced station access settings' if $cat eq 'stations'; + return 'Advanced network watchdog settings' if $cat eq 'network'; + + return 'Advanced settings'; +} + +sub advanced_hidden_category_input( $ ) +{ + my $cat = $_[0]; + + return '' if ! defined( $cat ) || $cat eq '' || $cat eq 'all'; + + return '' . "\n"; +} + + + +sub cfg_int( $ ) +{ + my $v = $_[0]; + $v = '' unless defined $v; + $v =~ s/^\s+//; + $v =~ s/\s+$//; + return 0 if $v eq ''; + return oct( $v ) if $v =~ /^0x[0-9a-f]+$/i; + return int( $v ); +} + +sub cfg_checked( $$ ) +{ + my( $value, $mask ) = @_; + return ( cfg_int( $value ) & $mask ) ? ' CHECKED' : ''; +} + +sub html_selected( $$ ) +{ + return ( defined $_[0] && defined $_[1] && $_[0] eq $_[1] ) ? ' SELECTED' : ''; +} + +sub option_012( $ ) +{ + my $v = $_[0]; + $v = '0' unless defined $v && $v ne ''; + return + '' . "\n" . + '' . "\n" . + '' . "\n"; +} + +sub getconfiglines_without_section( $ ) +{ + my @lines = getconfig( $_[0] ); + foreach my $line ( @lines ) + { + $line =~ s/^\s*$_[0]\s+//; + } + return @lines; +} + $settings_nav_bar = settings_nav_bar(); sub kernel_network_interfaces() @@ -182,12 +288,515 @@ sub network_interface_options( $ ) return $html; } + +sub url_escape( $ ) +{ + my $s = $_[0]; + $s = '' unless defined $s; + $s =~ s/([^A-Za-z0-9_\.\-])/sprintf("%%%02X", ord($1))/eg; + return $s; +} + +sub js_escape( $ ) +{ + my $s = $_[0]; + $s = '' unless defined $s; + $s =~ s/\\/\\\\/g; + $s =~ s/'/\\'/g; + $s =~ s/\r/\\r/g; + $s =~ s/\n/\\n/g; + return $s; +} + +sub smart_find_executable( @ ) +{ + foreach my $p ( @_ ) + { + next if ! defined( $p ) || $p eq ''; + return $p if -x $p; + } + return ''; +} + +sub sanitize_cups_printer_name( $ ) +{ + my $s = $_[0]; + $s = '' unless defined $s; + $s =~ s/[^-_\.A-Za-z0-9]//g; + return $s; +} + +sub cups_queue_name( $ ) +{ + my $s = sanitize_cups_printer_name( $_[0] ); + $s = uc( $s ); + $s =~ s/[^A-Z0-9_\-]/_/g; + $s = 'PRINTQ' if $s eq ''; + $s = substr( $s, 0, 47 ); + return $s; +} + +sub cups_print_command( $ ) +{ + my $printer = sanitize_cups_printer_name( $_[0] ); + my $template = $smart_cups_print_command_template; + + $template = '/usr/bin/lp -d %p -' unless defined( $template ) && $template ne ''; + $template =~ s/%p/$printer/g; + + return $template; +} + +sub cups_add_printer( $$$ ) +{ + my( $printers, $seen, $name ) = @_; + + return if ! defined( $name ); + $name =~ s/^\s+//; + $name =~ s/\s+$//; + return if $name eq ''; + return if $name =~ /[^-_\.A-Za-z0-9]/; + + my $queue = cups_queue_name( $name ); + + my $name_key = lc( $name ); + my $queue_key = lc( $queue ); + + # Deduplicate by both the original CUPS name and the generated MARS_NWE + # queue name. This avoids duplicates when the same printer is discovered + # through lpstat -e and a localized lpstat -p fallback. + return if $seen->{'name:' . $name_key}; + return if $seen->{'queue:' . $queue_key}; + + push( @$printers, { + name => $name, + queue => $queue, + command => cups_print_command( $name ), + } ); + + $seen->{'name:' . $name_key} = 1; + $seen->{'queue:' . $queue_key} = 1; +} + +sub cups_printers() +{ + my @printers = (); + my %seen = (); + + return @printers if ! defined( $smart_cups_enable ) || !$smart_cups_enable; + return @printers if ! defined( $smart_cups_lpstat_path ) || $smart_cups_lpstat_path eq ''; + return @printers if ! -x $smart_cups_lpstat_path; + + # Prefer "lpstat -e": it prints only destination names and is language + # independent. If it returns at least one printer, do not run fallback + # parsers, because some CUPS versions/locales can expose aliases there. + if( open( my $fh, '-|', $smart_cups_lpstat_path, '-e' ) ) + { + while( my $line = <$fh> ) + { + chomp( $line ); + $line =~ s/^\s+//; + $line =~ s/\s+$//; + + next if $line eq ''; + next if $line =~ /[\r\n]/; + + cups_add_printer( \@printers, \%seen, $line ); + } + + close( $fh ); + } + + return @printers if scalar( @printers ) > 0; + + # Fallback: "lpstat -v" is also mostly language independent because the + # destination name follows "for :" on many systems. + if( open( my $fh, '-|', $smart_cups_lpstat_path, '-v' ) ) + { + while( my $line = <$fh> ) + { + chomp( $line ); + + if( $line =~ /\bfor\s+([^:\s]+)\s*:/i ) + { + cups_add_printer( \@printers, \%seen, $1 ); + } + } + + close( $fh ); + } + + return @printers if scalar( @printers ) > 0; + + # Last fallback: parse localized "lpstat -p" output. English starts with + # "printer ", German starts with "Drucker ". + if( open( my $fh, '-|', $smart_cups_lpstat_path, '-p' ) ) + { + while( my $line = <$fh> ) + { + chomp( $line ); + + if( $line =~ /^(?:printer|Drucker)\s+(\S+)/i ) + { + cups_add_printer( \@printers, \%seen, $1 ); + } + } + + close( $fh ); + } + + return @printers; +} + +sub cups_import_rows() +{ + my $html = ''; + my @printers = cups_printers(); + + if( scalar( @printers ) == 0 ) + { + return qq|\t\n\t\tCUPS printers detected on host\n\t\n\t\n\t\tCUPS support is enabled, but no printers were returned by lpstat.\n\t\n|; + } + + $html .= qq|\t\n\t\tCUPS printers detected on host\n\t\n|; + + foreach my $printer ( @printers ) + { + my $name = ref( $printer ) eq 'HASH' ? $printer->{name} : $printer; + my $queue = ref( $printer ) eq 'HASH' ? $printer->{queue} : cups_queue_name( $printer ); + my $cmd = ref( $printer ) eq 'HASH' ? $printer->{command} : cups_print_command( $printer ); + my $href = '/settings/queues/add_new?cups_printer=' . url_escape( $name ); + + $html .= "\t\n"; + $html .= "\t\t" . html_escape( $name ) . "
Queue: " . html_escape( $queue ) . "   Command: " . html_escape( $cmd ) . "\n"; + $html .= "\t\tAdd as print queue\n"; + $html .= "\t\n"; + } + + return $html; +} + +sub cups_select_html( $ ) +{ + my $current = sanitize_cups_printer_name( $_[0] ); + my @printers = cups_printers(); + my $html = ''; + my $js = ''; + + return ( '', '' ) if scalar( @printers ) == 0; + + $html .= qq||; + + return ( $html, $js ); +} + +sub ipx_interface_info( $ ) +{ + my $want = $_[0]; + my %info = (); + + return %info if ! defined( $want ) || $want eq ''; + + if( open( my $fh, '<', '/proc/net/ipx/interface' ) ) + { + while( my $line = <$fh> ) + { + chomp( $line ); + $line =~ s/^\s+//; + $line =~ s/\s+$//; + + next if $line eq ''; + next if $line =~ /^Network\s+Node_Address\s+Primary\s+Device\s+Frame_Type/i; + + my @fields = split( /\s+/, $line ); + next if scalar( @fields ) < 5; + + my $network = $fields[0]; + my $dev = $fields[3]; + my $frame = $fields[4]; + + next if ! defined( $dev ) || $dev ne $want; + next if lc( $dev ) eq 'internal'; + + $info{network} = $network; + $info{frame} = $frame; + last; + } + + close( $fh ); + } + + return %info; +} + +sub ipx_device_import_rows() +{ + my $html = ''; + my @ifaces = ipx_enabled_interfaces(); + + if( scalar( @ifaces ) == 0 ) + { + return qq|\t\n\t\tIPX interfaces detected on host\n\t\n\t\n\t\tNo active IPX interfaces were found in /proc/net/ipx/interface.\n\t\n|; + } + + $html .= qq|\t\n\t\tIPX interfaces detected on host\n\t\n|; + + foreach my $iface ( @ifaces ) + { + my %info = ipx_interface_info( $iface ); + my $net = $info{network}; + my $frame = $info{frame}; + my $delay = 1; + + $net = '0x0' if ! defined( $net ) || $net eq ''; + $frame = '802.2' if ! defined( $frame ) || $frame eq '' || lc( $frame ) eq 'none'; + + my $href = '/settings/devices/add_new?ipx_iface=' . url_escape( $iface ); + + $html .= "\t\n"; + $html .= "\t\t" . html_escape( $iface ) . "
Config line: 4 " . html_escape( $net ) . " " . html_escape( $iface ) . " " . html_escape( $frame ) . " " . html_escape( $delay ) . "\n"; + $html .= "\t\tAdd as device\n"; + $html .= "\t\n"; + } + + return $html; +} + +sub ipx_device_defaults_from_query() +{ + my %defaults = (); + + $defaults{number} = ''; + $defaults{interface} = ''; + $defaults{frametype} = '802.2'; + $defaults{delay} = 1; + + if( defined( $p{ipx_iface} ) && $p{ipx_iface} ne '' ) + { + my $iface = $p{ipx_iface}; + $iface =~ s/[^-_\.A-Za-z0-9]//g; + + my %info = ipx_interface_info( $iface ); + + $defaults{interface} = $iface; + $defaults{number} = defined( $info{network} ) && $info{network} ne '' ? $info{network} : '0x0'; + $defaults{frametype} = defined( $info{frame} ) && $info{frame} ne '' && lc( $info{frame} ) ne 'none' ? $info{frame} : '802.2'; + $defaults{delay} = 1; + } + + return %defaults; +} + + +sub smart_bindery_values() +{ + my( $bind_server, $bind_user, $bind_pass ) = ( '', '', '' ); + + if( open( my $fh, '<' . $smart_nwclient_path ) ) + { + my $line = <$fh>; + close( $fh ); + + chomp( $line ) if defined( $line ); + ( $bind_server, $bind_user, $bind_pass ) = split( '[/ ]', $line ) if defined( $line ); + } + + $bind_server = '' unless defined( $bind_server ); + $bind_user = '' unless defined( $bind_user ); + $bind_pass = '' unless defined( $bind_pass ); + + return( $bind_server, $bind_user, $bind_pass ); +} + +sub sync_server_hint_row( $$$$ ) +{ + my( $checkbox_name, $current_name, $other_name, $direction ) = @_; + + $current_name = '' unless defined( $current_name ); + $other_name = '' unless defined( $other_name ); + + my $msg = ''; + + if( $direction eq 'general_to_smart' ) + { + $msg = 'Also update the SMArT bindery server when saving. Current SMArT bindery server: '; + $msg .= $other_name ne '' ? '' . html_escape( $other_name ) . '' : 'not set'; + } + else + { + $msg = 'Also update the MARS_NWE server name when saving. Current MARS_NWE server name: '; + $msg .= $other_name ne '' ? '' . html_escape( $other_name ) . '' : 'not set'; + } + + return qq|\t\n\t\tKeep server names in sync:
$msg\n\t\tYes \n\t\n|; +} + + +sub unix_user_import_rows() +{ + my $html = ''; + my @users = unix_userlist(); + my %existing = (); + my @candidates = (); + + foreach my $line ( getconfig( 13 ) ) + { + my @f = split( ' ', $line ); + $existing{lc( $f[1] )} = 1 if defined( $f[1] ) && $f[1] ne ''; + } + + foreach my $u ( @users ) + { + next if ! defined( $u->{name} ) || $u->{name} eq ''; + next if defined( $u->{uid} ) && $u->{uid} < 1000; + next if lc( $u->{name} ) eq 'nobody'; + next if lc( $u->{name} ) eq 'root'; + next if $existing{lc( $u->{name} )}; + + push( @candidates, $u ); + } + + if( scalar( @candidates ) == 0 ) + { + return qq|\t\n\t\tUnix users detected on host\n\t\n\t\n\t\tNo additional local Unix users were found for import.\n\t\n|; + } + + $html .= qq|\t\n\t\tUnix users detected on host\n\t\n|; + + foreach my $u ( @candidates ) + { + my $name = $u->{name}; + my $uid = $u->{uid}; + my $gecos = defined( $u->{gecos} ) ? $u->{gecos} : ''; + $gecos =~ s/,.*$//; + + my $href = '/settings/users_import/' . url_escape( $name ); + + $html .= "\t\n"; + $html .= "\t\t" . html_escape( $name ) . "
UID: " . html_escape( $uid ) . ""; + $html .= "   " . html_escape( $gecos ) if $gecos ne ''; + $html .= "\n"; + $html .= "\t\tAdd as MARS_NWE user\n"; + $html .= "\t\n"; + } + + return $html; +} + +sub unix_user_defaults_from_query() +{ + my %defaults = (); + + $defaults{name} = ''; + $defaults{unix_user} = ''; + $defaults{fullname} = ''; + + my $want = ''; + + # Preferred import route: + # /settings/users_import/ + if( defined( $c[1] ) && $c[1] eq 'users_import' && defined( $c[2] ) && $c[2] ne '' ) + { + $want = $c[2]; + } + # Compatibility route: + # /settings/users/add_new/ + elsif( defined( $c[3] ) && $c[3] ne '' ) + { + $want = $c[3]; + } + elsif( defined( $p{unix_user} ) && $p{unix_user} ne '' ) + { + $want = $p{unix_user}; + } + + if( $want ne '' ) + { + $want =~ s/[^-_\.A-Za-z0-9]//g; + + foreach my $u ( unix_userlist() ) + { + next if ! defined( $u->{name} ) || $u->{name} ne $want; + + my $gecos = defined( $u->{gecos} ) ? $u->{gecos} : ''; + $gecos =~ s/,.*$//; + + $defaults{name} = uc( $u->{name} ); + $defaults{name} =~ s/[^-_\.A-Za-z0-9]//g; + $defaults{unix_user} = $u->{name}; + $defaults{fullname} = $gecos; + last; + } + } + + return %defaults; +} + + +sub selected_attr( $$ ) +{ + my( $a, $b ) = @_; + + $a = '' unless defined( $a ); + $b = '' unless defined( $b ); + + return $a eq $b ? ' SELECTED' : ''; +} + + +sub smart_group_checkbox_rows( $ ) +{ + my $server = $_[0]; + my $html = ''; + + my @groups = (); + my $cmd = 'nwbols -t 2 -S ' . $server; + + @groups = sort( split( "\n", `$cmd` ) ); + + foreach my $g ( @groups ) + { + my @f = split( ' ', $g ); + my $group = $f[0]; + + next if ! defined( $group ) || $group eq ''; + next if $group =~ /[^-_\.A-Za-z0-9]/; + + $html .= html_escape( $group ) . '
' . "\n"; + } + + if( $html eq '' ) + { + $html = 'No bindery groups found. Save the user first, then add groups later.
' . "\n"; + } + + return $html; +} + + sub handle_request() { if( $c[1] eq 'general' ) { $server_name = getconfigline( 2 ); $internal_net = getconfigline( 3 ); + my( $smart_bind_server_for_general, $smart_bind_user_for_general, $smart_bind_pass_for_general ) = smart_bindery_values(); + my $general_sync_server_row = sync_server_hint_row( 'sync_smart_bind_server', $server_name, $smart_bind_server_for_general, 'general_to_smart' ); ( $burst_read, $burst_write ) = split( ' ', getconfigline( 30 ) ); $timing_down = getconfigline( 210 ); $timing_warn = getconfigline( 211 ); @@ -336,6 +945,7 @@ $settings_nav_bar
+$general_sync_server_row @@ -599,6 +1209,9 @@ $settings_nav_bar
+ + Advanced precompiled / path settings + @@ -696,6 +1309,9 @@ $settings_nav_bar Disallow encryption
+ + Advanced security settings + @@ -867,6 +1483,9 @@ $root_list
+ + Advanced user / bindery settings + @@ -1124,6 +1743,9 @@ $settings_nav_bar Write to separate files (.1, .2, etc)
+ + Advanced network watchdog settings + @@ -1438,6 +2060,8 @@ EOF { if( $c[2] eq '' ) { + my $ipx_device_import_rows = ipx_device_import_rows(); + print < - Add new device + Add new device manually

+ Advanced device settings @@ -1516,13 +2142,42 @@ EOF } else { - $c = getconfigline( '4 ' . $c[2] ); - @c = split( ' ', $c ); - $interface_options = network_interface_options( $c[1] ); - - $c[2] =~ s/\.//g; - eval( '$frametype_' . $c[2] . ' = " SELECTED";' ); - + my $title = $c[2]; + my $number = ''; + my $interface = ''; + my $frametype = '802.2'; + my $delay = 1; + + if( $c[2] eq 'add_new' ) + { + my %defaults = ipx_device_defaults_from_query(); + $number = $defaults{number}; + $interface = $defaults{interface}; + $frametype = $defaults{frametype}; + $delay = $defaults{delay}; + } + else + { + my $line = getconfigline( '4 ' . $c[2] ); + my @dev = split( ' ', $line ); + + $number = $dev[0]; + $interface = $dev[1]; + $frametype = $dev[2]; + $delay = $dev[3]; + + $title = $number; + } + + $number = '' unless defined $number; + $interface = '' unless defined $interface; + $frametype = '802.2' unless defined $frametype && $frametype ne ''; + $delay = 1 unless defined $delay && $delay ne ''; + + my $frametype_key = $frametype; + $frametype_key =~ s/\.//g; + eval( '$frametype_' . $frametype_key . ' = " SELECTED";' ); + print < $settings_nav_bar -
+ @@ -1584,10 +2239,8 @@ $settings_nav_bar Network interface: @@ -1610,7 +2263,7 @@ $interface_options
Interface delay: @@ -1629,14 +2282,12 @@ $interface_options
EOF } } + elsif( $c[1] eq 'smart' ) { - open( FILE, '<' . $smart_nwclient_path ) or die "Could not open $smart_nwclient_path: $!"; - $x = ; - close( FILE ); - - chomp( $x ); - ( $bind_server, $bind_user, $bind_pass ) = split( '[/ ]', $x ); + ( $bind_server, $bind_user, $bind_pass ) = smart_bindery_values(); + my $smart_general_server_name = getconfigline( 2 ); + my $smart_sync_server_row = sync_server_hint_row( 'sync_general_server_name', $bind_server, $smart_general_server_name, 'smart_to_general' ); print <
+$smart_sync_server_row @@ -1822,6 +2482,14 @@ EOF } else { + my $group_rows = smart_group_checkbox_rows( $server ); + my %unix_defaults = unix_user_defaults_from_query(); + my $default_name = $unix_defaults{name}; + my $default_unix_user = $unix_defaults{unix_user}; + my $default_fullname = $unix_defaults{fullname}; + $default_name = '' unless defined( $default_name ); + $default_unix_user = '' unless defined( $default_unix_user ); + $default_fullname = '' unless defined( $default_fullname ); $unix_user_list = ''; $group_list = ''; @allgroups = sort( split( "\n", `nwbols -S $server -t 2` ) ); @@ -1848,15 +2516,36 @@ EOF } else { + $fullname = $default_fullname; + foreach $u ( unix_userlist() ) { - $unix_user_list .= "\t\t\t" . '' . "\n"; + if( defined( $default_unix_user ) && $default_unix_user ne '' && $u->{name} eq $default_unix_user ) + { + $unix_user_list .= "\t\t\t" . '' . "\n"; + } + else + { + $unix_user_list .= "\t\t\t" . '' . "\n"; + } } + + if( defined( $default_unix_user ) && $default_unix_user ne '' && $unix_user_list !~ /VALUE="\Q$default_unix_user\E"/ ) + { + $unix_user_list .= "\t\t\t" . '' . "\n"; + } + foreach $g ( @allgroups ) { $g =~ s/ .*//; + next if $g eq ''; $group_list .= "\t\t\t" . $g . '
' . "\n"; } + + if( $group_list eq '' ) + { + $group_list = "\t\t\t" . 'EVERYONE
' . "\n"; + } } print < +
- Device: $c[0] + Device: $title
@@ -1576,7 +2231,7 @@ $settings_nav_bar Network number:
-
+
-
- Manual override:
-
+
+ Use the IPX interfaces list on the Devices overview to prefill this value.
-
+
@@ -1738,8 +2390,15 @@ $settings_nav_bar EOF } - elsif( $c[1] eq 'users' ) + elsif( $c[1] eq 'users' || $c[1] eq 'users_import' ) { + if( $c[1] eq 'users_import' ) + { + $p{unix_user} = $c[2]; + $c[1] = 'users'; + $c[2] = 'add_new'; + } + my $unix_user_import_rows = unix_user_import_rows(); $server = get_server(); if( $c[2] eq '' ) @@ -1810,6 +2469,7 @@ EOF print < + $unix_user_import_rows Add new user
EOF @@ -1967,6 +2657,22 @@ $group_list
@@ -1917,7 +2607,7 @@ EOF Account name: -
+
+ + + EOF @@ -2144,7 +2850,7 @@ EOF Group name: -
+
EOF @@ -2251,6 +2957,7 @@ EOF EOF } + print cups_import_rows(); print < @@ -2268,11 +2975,20 @@ EOF { @all = sort( split( "\n", `nwbols -S $server` ) ); $man_list = ''; + $queue_name_value = ''; + $selected_cups_printer = sanitize_cups_printer_name( $p{cups_printer} ); if( $c[2] ne 'add_new' ) { $unix_print = read_property_string( $c[2], 3, 'Q_UNIX_PRINT' ); $spool_dir = read_property_string( $c[2], 3, 'Q_DIRECTORY' ); } + elsif( $selected_cups_printer ne '' ) + { + $queue_name_value = cups_queue_name( $selected_cups_printer ); + $unix_print = cups_print_command( $selected_cups_printer ); + } + + ( $cups_select, $cups_js ) = cups_select_html( $selected_cups_printer ); print < + $settings_nav_bar @@ -2332,19 +3068,36 @@ EOF Queue name: -
+
EOF } + print < + + CUPS printer:
+ Select a host printer to generate the matching lp command. + + + $cups_select
+ + +EOF + } print < Unix printing command: -
+
+ Example for CUPS: /usr/bin/lp -d printer - @@ -2371,6 +3124,196 @@ EOF EOF } } + + elsif( $c[1] eq 'advanced' ) + { + my $advanced_category = advanced_category(); + my $advanced_title = advanced_title( $advanced_category ); + my $advanced_hidden = advanced_hidden_category_input( $advanced_category ); + + my $device_flags = getconfigline( 5 ); + my $security_flags = getconfigline( 8 ); + my $bindery_flags = getconfigline( 17 ); + my $queue_flags = getconfigline( 18 ); + my $max_dir_search_handles = getconfigline( 80 ); + my $conversion_tables = getconfigline( 50 ); + my $watchdogs = getconfigline( 310 ); + my $station_file = getconfigline( 400 ); + my $nearest_replies = getconfigline( 401 ); + my $connect_replies = getconfigline( 402 ); + + $device_flags = 0 if ! defined( $device_flags ) || $device_flags eq ''; + $security_flags = 0 if ! defined( $security_flags ) || $security_flags eq ''; + $bindery_flags = 0 if ! defined( $bindery_flags ) || $bindery_flags eq ''; + $queue_flags = 0 if ! defined( $queue_flags ) || $queue_flags eq ''; + + my $dev_keep = ( $device_flags & 1 ) ? ' CHECKED' : ''; + my $dev_auto = ( $device_flags & 2 ) ? ' CHECKED' : ''; + my $dev_remove_all = ( $device_flags & 4 ) ? ' CHECKED' : ''; + + my $sec_supervisor_ignore = ( $security_flags & 0x8 ) ? ' CHECKED' : ''; + my $sec_2gb_free = ( $security_flags & 0x40 ) ? ' CHECKED' : ''; + my $sec_int17 = ( $security_flags & 0x200 ) ? ' CHECKED' : ''; + my $sec_delete_open = ( $security_flags & 0x2 ) ? ' CHECKED' : ''; + my $sec_rename_open = ( $security_flags & 0x4 ) ? ' CHECKED' : ''; + + my $bindery_empty_scripts = ( $bindery_flags & 1 ) ? ' CHECKED' : ''; + my $queue_no_banner = ( $queue_flags & 1 ) ? ' CHECKED' : ''; + + my $nearest_0 = $nearest_replies eq '0' ? ' SELECTED' : ''; + my $nearest_1 = $nearest_replies eq '1' ? ' SELECTED' : ''; + my $nearest_2 = $nearest_replies eq '2' ? ' SELECTED' : ''; + + my $connect_0 = $connect_replies eq '0' ? ' SELECTED' : ''; + my $connect_1 = $connect_replies eq '1' ? ' SELECTED' : ''; + my $connect_2 = $connect_replies eq '2' ? ' SELECTED' : ''; + + my $print_server_rows = ''; + foreach my $ps ( getconfig( 22 ) ) + { + my $line = $ps; + $line =~ s/^22\s+//; + $print_server_rows .= html_escape( $line ) . "\n"; + } + + print < + +SMArT Advanced Settings + + + + +$settings_nav_bar + +
+$advanced_hidden + + + + + +EOF + + if( advanced_section_visible( $advanced_category, '5' ) ) + { + print < + + + +EOF + } + + if( advanced_section_visible( $advanced_category, '8' ) ) + { + print < + + + + + +EOF + } + + if( advanced_section_visible( $advanced_category, '17' ) ) + { + print < + +EOF + } + + if( advanced_section_visible( $advanced_category, '18' ) ) + { + print < + +EOF + } + + if( advanced_section_visible( $advanced_category, '22' ) ) + { + print < + +EOF + } + + if( advanced_section_visible( $advanced_category, '50' ) || advanced_section_visible( $advanced_category, '80' ) ) + { + print < +EOF + if( advanced_section_visible( $advanced_category, '50' ) ) + { + print qq|\t\n|; + } + if( advanced_section_visible( $advanced_category, '80' ) ) + { + print qq|\t\n|; + } + } + + if( advanced_section_visible( $advanced_category, '310' ) ) + { + print qq|\t\n|; + print qq|\t\n|; + } + + if( advanced_section_visible( $advanced_category, '400' ) || advanced_section_visible( $advanced_category, '401' ) || advanced_section_visible( $advanced_category, '402' ) ) + { + print < +EOF + if( advanced_section_visible( $advanced_category, '400' ) ) + { + print qq|\t\n|; + } + if( advanced_section_visible( $advanced_category, '401' ) ) + { + print < +EOF + } + if( advanced_section_visible( $advanced_category, '402' ) ) + { + print < +EOF + } + } + + print < + + + +
$advanced_title
IPX device flags
Keep IPX devices/routes on stop
Allow automatic kernel IPX interface creation
Remove all IPX routes/devices on stop
Security / compatibility flags
Ignore station/time restrictions for supervisor
Limit volume free space information to 2 GB
Enable direct INT17 printing for NETX clients
Allow deleting open files (advanced)
Allow renaming open files (advanced)
User / bindery flags
Create empty login scripts when missing
Print queue flags
Always disable print banner
Print server entries

One entry per line, without leading section number 22.
Precompiled / path settings
Conversion table file
Maximum directory search handles
Watchdog behavior
Watchdog ticks
0 = always, -1 = never, positive value = only below ticks.
Station access control
Station file
Nearest server replies
Connection replies

+
+ + + +EOF + } + else { error( 404 ); diff --git a/smart.conf.cmake b/smart.conf.cmake index 10f7915..b0d5371 100644 --- a/smart.conf.cmake +++ b/smart.conf.cmake @@ -79,6 +79,23 @@ $smart_systemctl_path = '@SYSTEMCTL_EXECUTABLE@'; # Uncomment and adjust only if a non-standard location must be used. # $smart_perl_path = '@MARS_NWE_INSTALL_FULL_LIBEXECDIR@/smart'; +# ------------------------------------------------------------ +# Host printer / CUPS utility integration +# ------------------------------------------------------------ + +# Enable CUPS host-printer discovery in the SMArT queue UI. +# This value is generated from cmake/modules/cupsutils.cmake. +# 1 = enabled, 0 = disabled +$smart_cups_enable = '@SMART_CUPS_ENABLE@'; + +# lpstat executable used to discover local CUPS printers for the queue UI. +$smart_cups_lpstat_path = '@CUPS_LPSTAT_EXECUTABLE@'; + +# Command template used when SMArT creates a print queue from a CUPS printer. +# %p is replaced with the sanitized CUPS printer name. +# The trailing '-' makes lp read the print job from stdin. +$smart_cups_print_command_template = '@CUPS_LP_EXECUTABLE@ -d %p -'; + # ------------------------------------------------------------ # nwwebui listener settings # ------------------------------------------------------------ diff --git a/smart_userlist.c b/smart_userlist.c new file mode 100644 index 0000000..133d7d3 --- /dev/null +++ b/smart_userlist.c @@ -0,0 +1,171 @@ +/* + SMArT + + List local/NSS users for the WebUI. + + PAM itself cannot enumerate users. User enumeration is done through NSS + getpwent(), so /etc/nsswitch.conf is honored (files, sss, ldap, nis, ...). + Optionally, each user can be checked with pam_acct_mgmt() against the "smart" + PAM service. + + Output format: + usernameuidgidgecoshomeshell +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static int empty_conv(int num_msg, const struct pam_message **msg, + struct pam_response **resp, void *appdata_ptr) +{ + struct pam_response *reply; + + (void) msg; + (void) appdata_ptr; + + if (num_msg <= 0) { + *resp = NULL; + return PAM_SUCCESS; + } + + reply = calloc((size_t) num_msg, sizeof(struct pam_response)); + if (reply == NULL) { + return PAM_BUF_ERR; + } + + *resp = reply; + return PAM_SUCCESS; +} + +static int pam_account_ok(const char *service, const char *user) +{ + struct pam_conv conv = { empty_conv, NULL }; + pam_handle_t *pamh = NULL; + int rc; + + rc = pam_start(service, user, &conv, &pamh); + if (rc == PAM_SUCCESS) { + rc = pam_acct_mgmt(pamh, PAM_SILENT); + } + + if (pamh != NULL) { + pam_end(pamh, rc); + } + + return rc == PAM_SUCCESS; +} + +static void print_sanitized(const char *s) +{ + const unsigned char *p = (const unsigned char *) (s != NULL ? s : ""); + + while (*p != '\0') { + if (*p == '\t' || *p == '\n' || *p == '\r') { + putchar(' '); + } else { + putchar((int) *p); + } + p++; + } +} + +static int is_safe_name(const char *s) +{ + const unsigned char *p = (const unsigned char *) s; + + if (s == NULL || *s == '\0') { + return 0; + } + + while (*p != '\0') { + if (!( (*p >= 'A' && *p <= 'Z') || + (*p >= 'a' && *p <= 'z') || + (*p >= '0' && *p <= '9') || + *p == '_' || *p == '-' || *p == '.' )) { + return 0; + } + p++; + } + + return 1; +} + +int main(int argc, char **argv) +{ + struct passwd *pw; + uid_t min_uid = 1000; + int include_system = 0; + int pam_check = 0; + const char *pam_service = "smart"; + int i; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "--all") == 0) { + include_system = 1; + min_uid = 0; + } else if (strcmp(argv[i], "--min-uid") == 0 && i + 1 < argc) { + char *end = NULL; + unsigned long v = strtoul(argv[++i], &end, 10); + if (end == NULL || *end != '\0') { + fprintf(stderr, "Invalid --min-uid value\n"); + return 2; + } + min_uid = (uid_t) v; + } else if (strcmp(argv[i], "--pam-check") == 0) { + pam_check = 1; + } else if (strcmp(argv[i], "--pam-service") == 0 && i + 1 < argc) { + pam_service = argv[++i]; + } else { + fprintf(stderr, + "Usage: %s [--all] [--min-uid UID] [--pam-check] [--pam-service SERVICE]\n", + argv[0]); + return 2; + } + } + + errno = 0; + setpwent(); + + while ((pw = getpwent()) != NULL) { + if (!is_safe_name(pw->pw_name)) { + continue; + } + + if (!include_system && pw->pw_uid < min_uid) { + continue; + } + + if (!include_system && + (strcmp(pw->pw_name, "root") == 0 || strcmp(pw->pw_name, "nobody") == 0)) { + continue; + } + + if (pam_check && !pam_account_ok(pam_service, pw->pw_name)) { + continue; + } + + print_sanitized(pw->pw_name); + printf("\t%lu\t%lu\t", (unsigned long) pw->pw_uid, (unsigned long) pw->pw_gid); + print_sanitized(pw->pw_gecos); + putchar('\t'); + print_sanitized(pw->pw_dir); + putchar('\t'); + print_sanitized(pw->pw_shell); + putchar('\n'); + } + + endpwent(); + + if (errno != 0) { + perror("getpwent"); + return 1; + } + + return 0; +} diff --git a/static/icon-configh.svg b/static/icon-configh.svg new file mode 100644 index 0000000..9195096 --- /dev/null +++ b/static/icon-configh.svg @@ -0,0 +1,17 @@ + diff --git a/static/icon-devices.svg b/static/icon-devices.svg new file mode 100644 index 0000000..20dd28a --- /dev/null +++ b/static/icon-devices.svg @@ -0,0 +1,19 @@ + diff --git a/static/icon-dirs.svg b/static/icon-dirs.svg new file mode 100644 index 0000000..f73e46a --- /dev/null +++ b/static/icon-dirs.svg @@ -0,0 +1,18 @@ + diff --git a/static/icon-general.svg b/static/icon-general.svg new file mode 100644 index 0000000..2bc0b09 --- /dev/null +++ b/static/icon-general.svg @@ -0,0 +1,18 @@ + diff --git a/static/icon-groups.svg b/static/icon-groups.svg new file mode 100644 index 0000000..4086c88 --- /dev/null +++ b/static/icon-groups.svg @@ -0,0 +1,18 @@ + diff --git a/static/icon-logging.svg b/static/icon-logging.svg new file mode 100644 index 0000000..cb7ab98 --- /dev/null +++ b/static/icon-logging.svg @@ -0,0 +1,19 @@ + diff --git a/static/icon-queues.svg b/static/icon-queues.svg new file mode 100644 index 0000000..6389200 --- /dev/null +++ b/static/icon-queues.svg @@ -0,0 +1,20 @@ + diff --git a/static/icon-security.svg b/static/icon-security.svg new file mode 100644 index 0000000..3657465 --- /dev/null +++ b/static/icon-security.svg @@ -0,0 +1,17 @@ + diff --git a/static/icon-service.svg b/static/icon-service.svg new file mode 100644 index 0000000..253acba --- /dev/null +++ b/static/icon-service.svg @@ -0,0 +1,23 @@ + diff --git a/static/icon-smart.svg b/static/icon-smart.svg new file mode 100644 index 0000000..4bfb5d9 --- /dev/null +++ b/static/icon-smart.svg @@ -0,0 +1,18 @@ + diff --git a/static/icon-start.svg b/static/icon-start.svg new file mode 100644 index 0000000..6210a19 --- /dev/null +++ b/static/icon-start.svg @@ -0,0 +1,22 @@ + diff --git a/static/icon-stations.svg b/static/icon-stations.svg new file mode 100644 index 0000000..f905af0 --- /dev/null +++ b/static/icon-stations.svg @@ -0,0 +1,19 @@ + diff --git a/static/icon-susers.svg b/static/icon-susers.svg new file mode 100644 index 0000000..48c44e3 --- /dev/null +++ b/static/icon-susers.svg @@ -0,0 +1,18 @@ + diff --git a/static/icon-users.svg b/static/icon-users.svg new file mode 100644 index 0000000..f40d566 --- /dev/null +++ b/static/icon-users.svg @@ -0,0 +1,19 @@ + diff --git a/static/icon-volumes.svg b/static/icon-volumes.svg new file mode 100644 index 0000000..aadd76f --- /dev/null +++ b/static/icon-volumes.svg @@ -0,0 +1,19 @@ + diff --git a/static/menu.html b/static/menu.html index b56a6be..0736bbc 100644 --- a/static/menu.html +++ b/static/menu.html @@ -9,47 +9,219 @@
-
-
-

Main menu

-

SMArT configuration navigation with the original explanations preserved.

+
+
+

Main menu

+

Choose a section from the icon list. The explanation opens here on the left, and the editor opens on the right.

+
+ SMArT logo
- SMArT logo -
-
- -
-

General settings

-
Open settings
+ +
+ + +
+
+
+

Setup first

+

Explanation on the left, editor opens in the right pane.

+
+
+
+
+ -
+
+
+

Fill SMArT settings first

+
Before editing users, groups, bindery objects, trustees or print queues, configure the SMArT settings first.
+
+
+

Bindery / Supervisor access

+
SMArT needs the NetWare bindery server name, the supervisor login and the supervisor password. Use the supervisor password that is configured for your MARS_NWE server in nwserv.conf. Without this, SMArT can still show configuration pages, but operations which talk to the running server can fail.
+
+
+

Why this matters

+
User, group and trustee actions use the MARS_NWE tools against the bindery. If the bindery credentials are missing or wrong, SMArT cannot reliably create objects, update memberships, set passwords or modify trustees.
+
+
+

Recommended order

+
+
    +
  1. Open SMArT settings.
  2. +
  3. Set the nwserv.conf path if needed.
  4. +
  5. Enter bindery server, supervisor user and supervisor password.
  6. +
  7. Save, then continue with users, groups, volumes, trustees and queues.
  8. +
+
+
+
+
+
+
+
+
Service control
+

MARS_NWE service

+
+ Open start page +
+
+
+

Start, stop, restart and status

+
Use this page to control the systemd service for the running MARS_NWE server.
+
+
+

Available actions

+
+
    +
  • status shows the current service state.
  • +
  • start starts the MARS_NWE service.
  • +
  • stop waits until the service is really stopped.
  • +
  • restart restarts the service and then shows the final status.
  • +
+
+
+
+

When to use it

+
After changing nwserv.conf, restart the service so the server reloads the changed configuration. Use the start page buttons on the right to run start, stop, restart or status.
+
+
+
+
+
+
+
Section
+

General settings

+
+ Open settings +
+

Servername

The servername is the name under which this server will show up when using @@ -119,39 +291,45 @@ Don't ask me what they mean, but they're hexadecimal, so don't forget to prepend 0x.
- - -
-

Directories

-
Open settings
+
+ -
+
Some directories for MARS_NWE files. The path cache directory is needed for Client-32 and the namespace calls, the spool directory is used for internal print queue handling.
- - -
-

Precompiled settings

-
Open settings
+
+ -
+
When you just leave these fields empty, the values in your config.h file will be used. If you want to change those settings without recompiling MARS_NWE, you can change them here.
- - -
-

Security

-
Open settings
+
+ -
+

Modes

Here you can change the standard modes for new files and directories. @@ -170,13 +348,15 @@ not-encrypted sending of passwords over the net.
On the Linux-side, passwords will only be stored in encrypted format.
- - -
-

User configuration

-
Open settings
+
+ -
+

Guest user

Here you can set the UID a user will get before logging in.
@@ -217,13 +397,15 @@ Only those Linux-logins will handled automatically that don't have a x or asterisk as their encrypted password.
- - -
-

Volumes

-
Open settings
+
+ -
+
The OS/2 additional namespace can be used by Windows 9x too. The 'no fixed i-nodes' option is necessary when exporting DOS or CD-ROM @@ -233,13 +415,15 @@ For more information about pipe filesystems you can take a look at MARS_NWE's documentation directory.
- - -
-

Devices

-
Open settings
+
+ -
+
This section contains information for the ipx-router built into mars_nwe and/or the external program nwrouted.
@@ -289,13 +473,15 @@ in internal device/routing table at runtime.
You don't have to set this in FreeBSD!
- - -
-

Logging

-
Open settings
+
+ -
+
MARS_NWE can keep a log file with error messages, click here to set what kind of messages must be logged and where.
@@ -305,48 +491,69 @@ According to nwserv.conf, the NWCLIENT tag must always be set to No debugging.
- - -
-

SMArT settings

-
Open settings
+
+ -
+
Some things have to be configured here before you can use SMArT.
- - -
-

Users

-
Open settings
+
+ -
+
+
+
Configure station file based nearest-server and connection replies.
+
+
+
+
+
+
Section
+

Users

+
+ Open settings +
+
You can edit the userlist from the bindery files here. This option will not change anything to the nwserv.conf configuration file.
- - -
-

Groups

-
Open settings
+
+ -
+
You can edit the group list from the bindery files here. This option will not change anything to the nwserv.conf configuration file.
- - -
-

Print queues

-
Open settings
+
+ -
+
Here you can edit the list of print queues. The things you have to fill in are:
    @@ -366,8 +573,58 @@ default directory.
- -
+
+
+
Tip: click an icon on the left to switch topics. The corresponding settings page is opened automatically in the editor pane on the right.
+
+
+ +