home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / Networking / SambaManager / Controller.m < prev    next >
Encoding:
Text File  |  1998-03-31  |  27.3 KB  |  978 lines

  1. /*
  2.     SambaManger. A graphical frontend to configure the NetInfo enhanced samba.
  3.     Copyright (C) 1998  Robert Frank
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 2 of the License, or
  8.     (at your option) any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.         
  19.         Robert Frank, frank@ifi.unibas.ch
  20. */
  21.  
  22. #import "Controller.h"
  23. #import "Users.h"
  24. #import "Printers.h"
  25. #import "Hosts.h"
  26. #import "Services.h"
  27. #import "DomainLogin.h"
  28. #import "NetInfoKeys.h"
  29. #import    "NIDirectory.h"
  30. #import    "NIProperty.h"
  31. #import <libc.h>
  32. #import <stdio.h>
  33. #import <string.h>
  34. #import <sys/types.h>
  35. #import <sys/stat.h>
  36. #import <pwd.h>
  37.  
  38. #define INETD_CONF    "/etc/inetd.conf"
  39. #define INETD_BACK    "/etc/inetd.conf~"
  40.  
  41. @implementation Controller
  42.  
  43. // ****************************************************
  44. // Local methods:
  45.  
  46. - (BOOL)menuActive:menuCell
  47. {
  48. id        theClass = [[[NXApp mainWindow] delegate] class];
  49. BOOL    hs = (theClass == [Hosts class]) || (theClass == [Services class]);
  50. BOOL    up = (theClass == [Users class]) || (theClass == [Printers class]); 
  51. BOOL    shouldBeEnabled = hs || up;
  52.  
  53.         if (shouldBeEnabled) {
  54.             if (menuCell == menuDelete)
  55.                 shouldBeEnabled = [[[NXApp mainWindow] delegate] isOld:self] && hs;
  56.             else if (menuCell == menuSaveToDomain)
  57.                 shouldBeEnabled = hs;
  58.             else if (menuCell == menuRevert)
  59.                 shouldBeEnabled = [[[NXApp mainWindow] delegate] isOld:self];
  60.             else
  61.                 shouldBeEnabled = (menuCell == menuClose) || [[NXApp mainWindow] isDocEdited];
  62.             
  63.             if ([menuCell isEnabled] != shouldBeEnabled) {
  64.                 [menuCell setEnabled:shouldBeEnabled];
  65.                 return YES;
  66.             }
  67.         } else if ([menuCell isEnabled] != shouldBeEnabled) {
  68.             [menuCell setEnabled:shouldBeEnabled];
  69.             return YES;
  70.         }
  71.         
  72.         return NO;
  73.  
  74. }
  75.  
  76. // The method called by the NIDirectory open method. It should check if the requested
  77. // object is already open.
  78. - (BOOL)niDirOk:(const char *)domain path:(const char *)directory
  79. {
  80. int    windows, i;
  81. id    obj;
  82.  
  83.             // Check all opened windows of this class. 
  84.             // (Can't use the window list; miniwindows don't have a delegate!)
  85.             // If we already have an open window, show it.
  86.             windows = [serviceList count];
  87.             for (i = 0; i < windows; i++) {
  88.                 obj = [serviceList objectAt:i];
  89.                 if ([obj isSame:directory inDomain:domain]) {
  90.                     [obj show:self];
  91.                     return NO;
  92.                 }
  93.             }
  94.             return YES;
  95. }
  96.  
  97. // Check if the given directory with its property value pairs exists.
  98. // If p2 is NULL, v2 is assumed to be the second value of p1.
  99. // Return self if the directory exists or was saved successfully.
  100. - checkNetInfoIn:(const char *)domainPath forDir:(const char *)dirName
  101.                                      prop1:(const char *)p1 val1:(const char *)v1
  102.                                      prop2:(const char *)p2 val2:(const char *)v2
  103.                                      prop3:(const char *)p3 val3:(const char *)v3
  104. {
  105. id                    retVal = self;
  106. NIDirectory    *NIDir = [[NIDirectory alloc] init:self dom:domainPath root:dirName dir:v1 errors:NO];
  107. NIProperty    *nameProp = [NIDir addProperty:p1];
  108.  
  109.         if (![[NIDir property:p1] values]) {
  110.             if (p2) {
  111.                 [nameProp updateValue:v1 at:0];
  112.                 [[NIDir addProperty:p2] updateValue:v2 at:0];
  113.                 [[NIDir addProperty:p3] updateValue:v3 at:0];
  114.             } else {
  115.                 [[nameProp updateValue:v1 at:0] updateValue:v2 at:1];
  116.                 [[NIDir addProperty:p3] updateValue:v3 at:0];
  117.             }
  118.             retVal = [NIDir save];
  119.         }
  120.         [NIDir close];
  121.         return retVal;
  122. }
  123.  
  124. - setNMBD:(const char *)line
  125. {
  126. unsigned char    token[1024];
  127. int                        d, r, i = 0, p = 0;
  128.  
  129.         while ((i < 6) && ((r = sscanf(line, "%s%n", token, &p)) != EOF)) {
  130.             i++;
  131.             line+= p;
  132.         }
  133.  
  134.         // Here we should have the fully qualified file name
  135.         if (r != EOF) {
  136.             [fieldnmbProgram setStringValue:token];
  137.             r = sscanf(line, "%s%n", token, &p); // Skip the daemon's name
  138.             line+= p;
  139.             r = sscanf(line, "%s%n", token, &p);
  140.             while (r != EOF) { // Options
  141.                 line+= p;
  142.                 if (*token == '-')
  143.                     switch (token[1]) {
  144.                         case 'd' : // Debug level
  145.                             while (*line && (*line <= ' ')) line++;
  146.                             r = sscanf(line, "%d%n", &d, &p);
  147.                             if ((d >= 10) || (*line == 'A'))
  148.                                 d = 10;
  149.                             [buttonNMBLogging setTitle:[[matrixNMBLogging findCellWithTag:d] title]];
  150.                             [matrixNMBLogging selectCellWithTag:d];
  151.                             line+= p;
  152.                             break;
  153.                         case 'n' : // Log method
  154.                             r = sscanf(line, "%s%n", token, &p);
  155.                             [fieldnmbNetBiosName setStringValue:token];
  156.                             line+= p;
  157.                             break;
  158.                         case 'l' : // Log file
  159.                             r = sscanf(line, "%s%n", token, &p);
  160.                             [fieldnmbLogFile setStringValue:token];
  161.                             line+= p;
  162.                             break;
  163.                         default  : ;
  164.                     }
  165.                 r = sscanf(line, "%s%n", token, &p);
  166.             }
  167.         }
  168.         
  169.         return self;
  170. }
  171.  
  172. - setSMBD:(const char *)line
  173. {
  174. unsigned char    token[1024], *t;
  175. int                        d, r, i = 0, p = 0;
  176.  
  177.         while ((i < 6) && ((r = sscanf(line, "%s%n", token, &p)) != EOF)) {
  178.             i++;
  179.             line+= p;
  180.         }
  181.  
  182.         // Here we should have the fully qualified file name
  183.         if (r != EOF) {
  184.             [fieldsmbProgram setStringValue:token];
  185.             r = sscanf(line, "%s%n", token, &p); // Skip the daemon's name
  186.             line+= p;
  187.             r = sscanf(line, "%s%n", token, &p);
  188.             while (r != EOF) { // Options
  189.                 line+= p;
  190.                 if (*token == '-')
  191.                     switch (token[1]) {
  192.                         case 'a' : // Log method
  193.                             [buttonSMBLogMethod setTitle:[[matrixSMBLogMethod findCellWithTag:1] title]];
  194.                             [matrixSMBLogMethod selectCellWithTag:1];
  195.                             break;
  196.                         case 'd' : // Debug level
  197.                             while (*line && (*line <= ' ')) line++;
  198.                             r = sscanf(line, "%d%n", &d, &p);
  199.                             if ((d >= 10) || (*line == 'A'))
  200.                                 d = 10;
  201.                             [buttonSMBLogging setTitle:[[matrixSMBLogging findCellWithTag:d] title]];
  202.                             [matrixSMBLogging selectCellWithTag:d];
  203.                             line+= p;
  204.                             break;
  205.                         case 'l' : // Log file
  206.                             r = sscanf(line, "%s%n", token, &p);
  207.                             [fieldsmbLogFile setStringValue:token];
  208.                             line+= p;
  209.                             break;
  210.                         case 'O' : // Socket options
  211.                             r = sscanf(line, "%s%n", token, &p);
  212.                             while ((r != EOF) && (*token != '-')) {
  213.                                 line+= p;
  214.                                 if (*token == '"')
  215.                                     t = token+1;
  216.                                 else
  217.                                     t = token;
  218.                                 if (!strncmp(t, "SO_KEEPALIVE", strlen("SO_KEEPALIVE")))
  219.                                     [checkKeepAlive setIntValue:1];
  220.                                 else if (!strncmp(t, "SO_REUSEADDR", strlen("SO_REUSEADDR")))
  221.                                     [checkReuse setIntValue:1];
  222.                                 else if (!strncmp(t, "SO_BROADCAST", strlen("SO_BROADCAST")))
  223.                                     [checkBroadcast setIntValue:1];
  224.                                 else if (!strncmp(t, "TCP_NODELAY", strlen("TCP_NODELAY")))
  225.                                     [checkNoDelay setIntValue:1];
  226.                                 else if (!strncmp(t, "SO_SNDBUF", strlen("SO_SNDBUF")))
  227.                                     [fieldSendBufSize setIntValue:atoi(t+strlen("SO_SNDBUF")+1)];
  228.                                 else if (!strncmp(t, "SO_RCVBUF", strlen("SO_RCVBUF")))
  229.                                     [fieldRecBufSize setIntValue:atoi(t+strlen("SO_RCVBUF")+1)];
  230.                                 else if (!strncmp(t, "SO_SNDLOWAT", strlen("SO_SNDLOWAT")))
  231.                                     [fieldSendLowWat setIntValue:atoi(t+strlen("SO_SNDLOWAT")+1)];
  232.                                 else if (!strncmp(t, "SO_RCVLOWAT", strlen("SO_RCVLOWAT")))
  233.                                     [fieldRecLowWat setIntValue:atoi(t+strlen("SO_RCVLOWAT")+1)];
  234.                                 r = sscanf(line, "%s%n", token, &p);
  235.                             }
  236.                             break;
  237.                         default  : ;
  238.                     }
  239.                 r = sscanf(line, "%s%n", token, &p);
  240.             }
  241.         }
  242.         
  243.         return self;
  244. }
  245.  
  246. - clearStartup
  247. {
  248.         // Clear all fields and reset popups.
  249.         [fieldnmbProgram setStringValue:""];
  250.         [fieldnmbNetBiosName setStringValue:""];
  251.         [buttonNMBLogging setTitle:[[matrixNMBLogging findCellWithTag:0] title]];
  252.         [matrixNMBLogging selectCellWithTag:0];
  253.         [fieldnmbLogFile setStringValue:""];
  254.         [fieldsmbProgram setStringValue:""];
  255.         [checkKeepAlive setIntValue:0];
  256.         [checkReuse setIntValue:0];
  257.         [checkBroadcast setIntValue:0];
  258.         [checkNoDelay setIntValue:0];
  259.         [fieldSendBufSize setStringValue:""];
  260.         [fieldRecBufSize setStringValue:""];
  261.         [fieldSendLowWat setStringValue:""];
  262.         [fieldRecLowWat setStringValue:""];
  263.         [buttonSMBLogging setTitle:[[matrixSMBLogging findCellWithTag:0] title]];
  264.         [matrixSMBLogging selectCellWithTag:0];
  265.         [buttonSMBLogMethod setTitle:[[matrixSMBLogMethod findCellWithTag:0] title]];
  266.         [matrixSMBLogMethod selectCellWithTag:0];
  267.         [fieldsmbLogFile setStringValue:""];
  268.  
  269.         // Set the buttons.
  270.         [buttonStop setEnabled:NO];
  271.         [buttonStart setEnabled:NO];
  272.         [buttonRemove setEnabled:NO];
  273.         [buttonRevert setEnabled:NO];
  274.         [buttonSave setEnabled:NO];
  275.  
  276.         [windowStartup setDocEdited:NO];
  277.  
  278.         return self;
  279. }
  280.  
  281. - (BOOL)alertChoice:(const char *)msg buttons:(BOOL)YesNo
  282. {
  283. int    choice =    NXRunAlertPanel([strings valueForStringKey:"Alert:Alert"],
  284.                                                             [strings valueForStringKey:msg],
  285.                                                             [strings valueForStringKey:YesNo?"Button:Yes":"Button:OK"],
  286.                                                             YesNo?[strings valueForStringKey:"Button:No"]:NULL, 
  287.                                                             NULL, INETD_CONF, strerror(errno));
  288.         return (choice == NX_ALERTDEFAULT);
  289. }
  290.  
  291. - (BOOL)smbdLine:(char *)buffer
  292. {
  293. BOOL                keep      = [checkKeepAlive state],
  294.                         reuse     = [checkReuse state],
  295.                         broadcast = [checkBroadcast state],
  296.                         noDelay   = [checkNoDelay state],
  297.                         logMode   = [[matrixSMBLogMethod selectedCell] tag];
  298. int                    d     = [[matrixSMBLogging selectedCell] tag],
  299.                         snd   = [fieldSendBufSize intValue],
  300.                         rcv   = [fieldRecBufSize intValue],
  301.                         sndlo = [fieldSendLowWat intValue],
  302.                         rcvlo = [fieldRecLowWat intValue],
  303.                         statRet;
  304. const char    *smbd = [fieldsmbProgram stringValue],
  305.                         *log  = [fieldsmbLogFile stringValue];
  306. struct stat    status;
  307. FILE                *pipe;
  308. char                pbuffer[4096];
  309.  
  310.         if (!*smbd || (d && !*log)) {
  311.             [self alertChoice:*log?"Message:No smb daemon":"Message:No smbd log file" buttons:NO];
  312.             return NO;
  313.         }
  314.         
  315.         // Try to execute the daemon. If it doesn't exist, return NO.
  316.         // If it doesn't return NetInfo ..., warn about using SambaManager.app.
  317.         status.st_mode = 0;
  318.         statRet = stat(smbd, &status);
  319.         if ((statRet != 0) || !(status.st_mode&S_IEXEC)) {
  320.             [self alertChoice:"Message:Cannot find smb daemon" buttons:NO];
  321.             return NO;
  322.         }
  323.         
  324.         (void)strcpy(pbuffer, smbd);
  325.         (void)strcat(pbuffer, " -V");
  326.         pipe = popen(pbuffer, "r");
  327.         fscanf(pipe, "%s", pbuffer);
  328.         pclose(pipe);
  329.         if (strcmp(pbuffer, "NetInfo"))
  330.             [self alertChoice:"Message:SMB daemon not NetInfo enhanced" buttons:NO];
  331.         
  332.         (void)strcpy(buffer, "netbios-ssn  stream  tcp  nowait  root  ");
  333.         (void)strcat(buffer, smbd);
  334.         if (logMode)
  335.             (void)strcat(buffer, " -a");
  336.         if (d < 10)
  337.             sprintf(buffer+strlen(buffer), " smbd -d %d", d);
  338.         else
  339.             (void)strcat(buffer," smbd -d All");
  340.         if (d)
  341.             sprintf(buffer+strlen(buffer), " -l %s", log);
  342.         if (keep | reuse | broadcast | noDelay | snd | rcv | sndlo | rcvlo) {
  343.             sprintf(buffer+strlen(buffer), " -O \"%s%s%s%s",
  344.                             keep?"SO_KEEPALIVE ":"", reuse?"SO_REUSEADDR ":"",
  345.                             broadcast?"SO_BROADCAST ":"", noDelay?"TCP_NODELAY ":"");
  346.             if (snd)
  347.                 sprintf(buffer+strlen(buffer), "SO_SNDBUF=%d ", snd);
  348.             if (rcv)
  349.                 sprintf(buffer+strlen(buffer), "SO_RCVBUF=%d ", rcv);
  350.             if (sndlo)
  351.                 sprintf(buffer+strlen(buffer), "SO_SNDLOWAT=%d ", sndlo);
  352.             if (rcvlo)
  353.                 sprintf(buffer+strlen(buffer), "SO_RCVLOWAT=%d ", rcvlo);
  354.             sprintf(buffer+strlen(buffer)-1, "\"");
  355.         }
  356.         (void)strcat(buffer, " -f /tmp/smbd.pid\n");
  357.         return YES;
  358. }
  359.  
  360. - (BOOL)nmbdLine:(char *)buffer
  361. {
  362. int                    d       = [[matrixNMBLogging selectedCell] tag],
  363.                         statRet;
  364. const char    *nmbd   = [fieldnmbProgram stringValue],
  365.                         *log    = [fieldnmbLogFile stringValue],
  366.                         *nbName = [fieldnmbNetBiosName stringValue];
  367. struct stat    status;
  368. FILE                *pipe;
  369. char                pbuffer[4096];
  370.  
  371.         if (!*nmbd || (d && !*log)) {
  372.             [self alertChoice:*log?"Message:No nmb daemon":"Message:No nmbd log file" buttons:NO];
  373.             return NO;
  374.         }
  375.         
  376.         // Try to execute the daemon. If it doesn't exist, return NO.
  377.         // If it doesn't return NetInfo ..., warn about using SambaManager.app.
  378.         status.st_mode = 0;
  379.         statRet = stat(nmbd, &status);
  380.         if ((statRet != 0) || !(status.st_mode&S_IEXEC)) {
  381.             [self alertChoice:"Message:Cannot find nmb daemon" buttons:NO];
  382.             return NO;
  383.         }
  384.         
  385.         (void)strcpy(pbuffer, nmbd);
  386.         (void)strcat(pbuffer, " -V");
  387.         pipe = popen(pbuffer, "r");
  388.         fscanf(pipe, "%s", pbuffer);
  389.         pclose(pipe);
  390.         if (strcmp(pbuffer, "NetInfo"))
  391.             [self alertChoice:"Message:NMB daemon not NetInfo enhanced" buttons:NO];
  392.         
  393.         (void)strcpy(buffer, "netbios-ns   dgram   udp  wait    root  ");
  394.         (void)strcat(buffer, nmbd);
  395.         sprintf(buffer+strlen(buffer), " nmbd -d %d", d);
  396.         if (d)
  397.             sprintf(buffer+strlen(buffer), " -l %s", log);
  398.         if (*nbName)
  399.             sprintf(buffer+strlen(buffer), " -n %s", nbName);
  400.         (void)strcat(buffer, " -f /tmp/nmbd.pid\n");
  401.         return YES;
  402. }
  403.  
  404. - scanEtcInetdConf:(int)mode
  405. // Mode is: 0 for reading, 1 for writing, 2 for stopping, 3 for starting, 4 for removing
  406. {
  407. NXStream            *rStream = NXMapFile(INETD_CONF, NX_READONLY),
  408.                             *wStream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  409. unsigned char    line[1024], c;
  410. char                    buf[MAXPATHLEN + 1];
  411. int                        i, both = 0, o, have = 0, smbd, nmbd;
  412. BOOL                    retVal = YES;
  413. FILE                    *pipe;
  414. struct passwd    *pwEnt;
  415. char                    salt[3];
  416.  
  417.         [windowStartup disableFlushWindow];
  418.  
  419.         if (!mode)
  420.             [self clearStartup];
  421.  
  422.         if (!rStream) {
  423.             NXCloseMemory(wStream, NX_FREEBUFFER);
  424.             [windowStartup reenableFlushWindow];
  425.             [windowStartup display];
  426.             return nil;
  427.         }
  428.  
  429.         c = NXGetc(rStream);
  430.         while (!NXAtEOS(rStream) && (both < 2)) {
  431.             while (!NXAtEOS(rStream) && (c <= ' ')) {
  432.                 NXPutc(wStream, c);
  433.                 c = NXGetc(rStream);
  434.             }
  435.             i = 0;
  436.             while (!NXAtEOS(rStream) && (i < 1024) && (c != '\n')) {
  437.                 line[i++] = c;
  438.                 c = NXGetc(rStream);
  439.             }
  440.             line[i] = '\0';
  441.             
  442.             o = ((*line == '#') && (*(line+1) == '!'))?2:0;
  443.             if ((*line == '#') && !o) {
  444.                 line[i++] = '\n';
  445.                 NXWrite(wStream, line, i);
  446.                 *line = '\0';
  447.             }
  448.             
  449.             if (*(line+o)) {
  450.                 smbd = !strncmp(line+o, SMNIP_NBSSN, strlen(SMNIP_NBSSN));
  451.                 nmbd = !strncmp(line+o, SMNIP_NBNS, strlen(SMNIP_NBNS));
  452.                 if (smbd || nmbd) {
  453.                     [buttonRemove setEnabled:!uid || !euid];
  454.                     [buttonStart setEnabled:o && (!uid || !euid)];
  455.                     [buttonStop setEnabled:!o && (!uid || !euid)];
  456.                     switch (mode) {
  457.                         case 0:
  458.                             if (smbd)
  459.                                 [self setSMBD:line+o];
  460.                             else
  461.                                 [self setNMBD:line+o];
  462.                             both++;
  463.                             break;
  464.                         case 1: // write
  465.                             have|= smbd?1:2;
  466.                             // We'll continue and back out before saving.
  467.                             if (smbd)
  468.                                 retVal&= [self smbdLine:line];
  469.                             else
  470.                                 retVal&= [self nmbdLine:line];
  471.                             NXWrite(wStream, line, strlen(line));
  472.                             break;
  473.                         case 2: // stop
  474.                             NXWrite(wStream, "#!", 2);
  475.                         case 3: // start
  476.                             NXWrite(wStream, line+o, i-o);
  477.                             NXPutc(wStream, '\n');
  478.                             break;
  479.                         case 4: // remove
  480.                         default: ;
  481.                     }
  482.                 } else {
  483.                     NXWrite(wStream, line, i);
  484.                     NXPutc(wStream, '\n');
  485.                 }
  486.             }
  487.             c = NXGetc(rStream);
  488.         }
  489.         
  490.         if (mode && retVal) {
  491.             if ((mode == 1) && !(have&1)) {
  492.                 retVal&= [self smbdLine:line];
  493.                 NXWrite(wStream, "#!", 2);
  494.                 NXWrite(wStream, line, strlen(line));
  495.             }
  496.             if (retVal && (mode == 1) && !(have&2)) {
  497.                 retVal&= [self nmbdLine:line];
  498.                 NXWrite(wStream, "#!", 2);
  499.                 NXWrite(wStream, line, strlen(line));
  500.             }
  501.             // If we are root (uid = 0) save. If we have set uid, validate the root password.
  502.             if (retVal && (uid && !euid) && !rootOk) {
  503.                 pwEnt = getpwuid(0);
  504.                 strncpy(salt, pwEnt->pw_passwd, 2);
  505.                 salt[2] = '\0';
  506.                 [fieldPassword selectText:self];
  507.                 i = [NXApp runModalFor:panelAuthenicate];
  508.                 [panelAuthenicate close];
  509.                 switch(i) {
  510.                     case NX_RUNSTOPPED:
  511.                         rootOk = retVal = !strcmp(crypt((char *)[fieldPassword stringValue], salt), pwEnt->pw_passwd);
  512.                         break;
  513.                     default: 
  514.                         retVal = NO;
  515.                 }
  516.             }
  517.  
  518.             if (retVal) {
  519.                 if (retVal = (rename(INETD_CONF, INETD_BACK) == 0)) {
  520.                     if (retVal = !NXSaveToFile(wStream, INETD_CONF))
  521.                         switch (mode) {
  522.                             case 1: // save
  523.                                 [windowStartup setDocEdited:NO];
  524.                                 [buttonRevert setEnabled:NO];
  525.                                 [buttonSave setEnabled:NO];
  526.                                 [buttonStart setEnabled:!have && (!uid || !euid)];
  527.                                 [buttonRemove setEnabled:have && (!uid || !euid)];
  528.                                 break;
  529.                             case 2: // stop
  530.                                 [buttonStop setEnabled:NO];
  531.                                 [buttonStart setEnabled:!uid || !euid];
  532.                                 break;
  533.                             case 3: // start
  534.                                 [buttonStart setEnabled:NO];
  535.                                 [buttonStop setEnabled:!uid || !euid];
  536.                                 break;
  537.                             case 4: // clear
  538.                                 [self clearStartup];
  539.                         }
  540.                     else 
  541.                         NXRunAlertPanel([strings valueForStringKey:"Alert:Alert"],
  542.                                                         [strings valueForStringKey:"Message:Could not save configuraton"],
  543.                                                         [strings valueForStringKey:"Button:OK"],
  544.                                                         NULL, NULL, INETD_CONF);
  545.                 } else 
  546.                     NXRunAlertPanel([strings valueForStringKey:"Alert:Alert"],
  547.                                                     [strings valueForStringKey:"Message:Could not rename"],
  548.                                                     [strings valueForStringKey:"Button:OK"],
  549.                                                     NULL, NULL, INETD_CONF, strerror(errno));
  550.             }
  551.         }
  552.         NXCloseMemory(wStream, NX_FREEBUFFER);
  553.         NXCloseMemory(rStream, NX_FREEBUFFER);
  554.  
  555.         // If no daemons set, search for them!
  556.         if (!*[fieldsmbProgram stringValue]) {
  557.             if (![[NXBundle mainBundle] getPath:buf forResource:"smbd" ofType:NULL])
  558.                 if (![NXBundle getPath:buf forResource:"smbd" ofType:NULL
  559.                                              inDirectory:"/LocalLibrary/SambaManager" withVersion:0])
  560.                     if (![NXBundle getPath:buf forResource:"smbd" ofType:NULL
  561.                                                  inDirectory:"/LocalLibrary/SambaManager/samba" withVersion:0])
  562.                         if (![NXBundle getPath:buf forResource:"smbd" ofType:NULL
  563.                                                      inDirectory:"/users/local/samba/bin" withVersion:0])
  564.                             *buf = '\0';
  565.             if (*buf) {
  566.                 [fieldsmbProgram setStringValue:buf];
  567.                 [windowStartup setDocEdited:YES];
  568.                 [buttonSave setEnabled:!uid || !euid];
  569.             }
  570.         }
  571.         if (!*[fieldnmbProgram stringValue]) {
  572.             if (![[NXBundle mainBundle] getPath:buf forResource:"nmbd" ofType:NULL])
  573.                 if (![NXBundle getPath:buf forResource:"nmbd" ofType:NULL
  574.                                              inDirectory:"/LocalLibrary/SambaManager" withVersion:0])
  575.                     if (![NXBundle getPath:buf forResource:"nmbd" ofType:NULL
  576.                                                  inDirectory:"/LocalLibrary/SambaManager/samba" withVersion:0])
  577.                         if (![NXBundle getPath:buf forResource:"nmbd" ofType:NULL
  578.                                                      inDirectory:"/users/local/samba/bin" withVersion:0])
  579.                             *buf = '\0';
  580.             if (*buf) {
  581.                 [fieldnmbProgram setStringValue:buf];
  582.                 [windowStartup setDocEdited:YES];
  583.                 [buttonSave setEnabled:!uid || !euid];
  584.             }
  585.         }
  586.         
  587.         [windowStartup reenableFlushWindow];
  588.         [windowStartup display];
  589.  
  590.         // Send a hangup to the inetd process.
  591.         if (retVal && (mode > 1)) {
  592.             have = (pipe = popen("/bin/ps ax | /bin/grep inetd | /bin/grep -v grep", "r")) != NULL;
  593.             i = -1;
  594.             if (have) {
  595.                 fscanf(pipe, "%d", &i);
  596.                 pclose(pipe);
  597.                 have = kill(i, SIGHUP) == 0;
  598.             }
  599.             // Warn that inetd wasn't restarted if no pipe or kill fails.
  600.             if (!have)
  601.                 if (i > 0)
  602.                     NXRunAlertPanel([strings valueForStringKey:"Alert:Alert"],
  603.                                                     [strings valueForStringKey:"Message:Could not signal inetd pid"],
  604.                                                     [strings valueForStringKey:"Button:OK"],
  605.                                                     NULL, NULL, i);
  606.                 else
  607.                     [self alertChoice:"Message:Could not signal inetd" buttons:NO];
  608.             // If disable, try to stop the daemons. Remove any pid files.
  609.             if ((mode == 2) || (mode == 4)) {
  610.                 if ((pipe = fopen("/tmp/nmbd.pid", "r")) != NULL) {
  611.                     if (fscanf(pipe, "%d", &i) == 1)
  612.                         kill(i, SIGKILL);
  613.                     fclose(pipe);
  614.                 }
  615.                 unlink("/tmp/nmbd.pid");
  616.                 if ((pipe = fopen("/tmp/smbd.pid", "r")) != NULL) {
  617.                     if (fscanf(pipe, "%d", &i) == 1)
  618.                         kill(i, SIGKILL);
  619.                     fclose(pipe);
  620.                 }
  621.                 unlink("/tmp/smbd.pid");
  622.             }
  623.         }
  624.         
  625.         return self;
  626. }
  627.  
  628. - markEdited:sender
  629. {
  630.         [windowStartup setDocEdited:YES];
  631.         [buttonSave setEnabled:!uid || !euid];
  632.         [buttonRevert setEnabled:YES];
  633.         return self;
  634. }
  635.  
  636. - openFilePath:(BOOL)dirsOnly field:outlet
  637. {
  638. const char    *docFileType[1] = {NULL};
  639. char                buffer[4096], hostName[128];
  640. id                    openPanel;
  641.  
  642.         openPanel = [[OpenPanel new] allowMultipleFiles:NO];
  643.         [openPanel chooseDirectories:dirsOnly];
  644.         [openPanel setTitle:[strings valueForStringKey:dirsOnly?"Title:Select Directory":"Title:Select File"]]; 
  645.     
  646.         switch([openPanel runModalForTypes:docFileType]) {
  647.             case NX_OKTAG:
  648.                 if (dirsOnly) {
  649.                     strcpy(buffer, [openPanel filename]);
  650.                     strcat(buffer, "/");
  651.                     if (gethostname(hostName, 128))
  652.                         strcpy(hostName, "log");
  653.                     strcat(buffer, hostName);
  654.                     [outlet setStringValue:buffer];
  655.                 } else
  656.                     [outlet setStringValue:[openPanel filename]];
  657.                 [self markEdited:self];
  658.             default: ;
  659.         }
  660.         return self;
  661. }
  662.  
  663. // Check and possibly set the NetInfo values for the samba daemons.
  664. - setNetInfo
  665. {
  666.     if ([self checkNetInfoIn:"." forDir:SMNI_SERVICES
  667.                         prop1:SMNIP_NAME val1:SMNIP_NBSSN
  668.                         prop2:SMNIP_PORT val2:"139"
  669.                         prop3:SMNIP_PROTOCOL val3:"tcp"])
  670.         if ([self checkNetInfoIn:"." forDir:SMNI_SERVICES
  671.                             prop1:SMNIP_NAME val1:SMNIP_NBNS
  672.                             prop2:SMNIP_PORT val2:"137"
  673.                             prop3:SMNIP_PROTOCOL val3:"udp"])
  674.             if ([self checkNetInfoIn:"." forDir:SMNIP_PROTOCOLS
  675.                                 prop1:SMNIP_NAME val1:"tcp"
  676.                                 prop2:NULL val2:"TCP"
  677.                                 prop3:SMNIP_NUMBER val3:"6"])
  678.                 if ([self checkNetInfoIn:"." forDir:SMNIP_PROTOCOLS
  679.                                     prop1:SMNIP_NAME val1:"udp"
  680.                                     prop2:NULL val2:"UDP"
  681.                                     prop3:SMNIP_NUMBER val3:"17"])
  682.                     return self;
  683.  
  684.     return nil;
  685. }
  686.  
  687. // ****************************************************
  688. // Other methods:
  689.  
  690. - removeFromServiceList:sender
  691. // Rmove the sender from the list of opened services.
  692. {
  693.         [serviceList removeObject:sender];
  694.         return self;
  695. }
  696.  
  697. // ****************************************************
  698. // Actions from the menus, window, and panel:
  699.  
  700. - cancelPassword:sender
  701. {
  702.         [NXApp abortModal];
  703.         return self;
  704. }
  705.  
  706. - okayPassword:sender
  707. {
  708.         [NXApp stopModal];
  709.         return self;
  710. }
  711.  
  712. - info:sender
  713. {
  714.     return self;
  715. }
  716.  
  717. - preferences:sender
  718. {
  719.     return self;
  720. }
  721.  
  722. - showStartup:sender
  723. {
  724.         [fieldnmbProgram selectText:self];
  725.         [windowStartup makeKeyAndOrderFront:self];
  726.         return self;
  727. }
  728.  
  729. - saveStartup:sender
  730. {
  731.         if ([self scanEtcInetdConf:1])
  732.         [self setNetInfo];
  733.             
  734.         return self;
  735. }
  736.  
  737. - revertStartup:sender
  738. {
  739.         [self scanEtcInetdConf:0];
  740.     return self;
  741. }
  742.  
  743. - openUser:sender
  744. {
  745.         return [serviceList addObject:[Users open:self at:&offset]];
  746. }
  747.  
  748. - openPrinter:sender
  749. {
  750.         return [serviceList addObject:[Printers open:self at:&offset]];
  751. }
  752.  
  753. - newHost:sender
  754. {
  755.         return [serviceList addObject:[Hosts new:self at:&offset]];
  756. }
  757.  
  758. - newService:sender
  759. {
  760.         return [serviceList addObject:[Services new:self at:&offset]];
  761. }
  762.  
  763. - openHost:sender
  764. {
  765.         return [serviceList addObject:[Hosts open:self at:&offset]];
  766. }
  767.  
  768. - openService:sender
  769. {
  770.         return [serviceList addObject:[Services open:self at:&offset]];
  771. }
  772.  
  773. - saveToDomain:sender
  774. {
  775.         if ([NXApp mainWindow] != nil)
  776.             [[[NXApp mainWindow] delegate] saveToDomain:self];
  777.         return self;
  778. }
  779.  
  780. - delete:sender
  781. {
  782.         if ([NXApp mainWindow] != nil)
  783.             [[[NXApp mainWindow] delegate] delete:self];
  784.     return self;
  785. }
  786.  
  787. - close:sender
  788. {
  789. id    obj;
  790.  
  791.         if ([NXApp mainWindow] != nil) {
  792.             obj = [[NXApp mainWindow] delegate];
  793.             if ([obj close:self])
  794.                 [obj free];
  795.         }
  796.         return self;
  797. }
  798.  
  799. // Remove a samba daemon from this system
  800. - remove:sender
  801. {
  802.         [self scanEtcInetdConf:4];
  803.         return self;
  804. }
  805.  
  806. - revert:sender
  807. {
  808.         if ([NXApp mainWindow] != nil)
  809.             [[[NXApp mainWindow] delegate] revert:self];
  810.     return self;
  811. }
  812.  
  813. - save:sender
  814. {
  815.         if ([NXApp mainWindow] != nil)
  816.             [[[NXApp mainWindow] delegate] save:self];
  817.     return self;
  818. }
  819.  
  820. - start:sender
  821. {
  822.         if ([windowStartup isDocEdited])
  823.             if ([self alertChoice:"Message:Save before enabling?" buttons:YES])
  824.                 if (![self saveStartup:self])
  825.                     return self;
  826.         [self scanEtcInetdConf:3];
  827.         return self;
  828. }
  829.  
  830. - stop:sender
  831. {
  832.         [self scanEtcInetdConf:2];
  833.         return self;
  834. }
  835.  
  836. - setNameDaemon:sender
  837. {
  838.         return [self openFilePath:NO field:fieldnmbProgram];
  839. }
  840.  
  841. - setNameLogging:sender
  842. {
  843.         return [self openFilePath:YES field:fieldnmbLogFile];
  844. }
  845.  
  846. - setSambaDaemon:sender
  847. {
  848.         return [self openFilePath:NO field:fieldsmbProgram];
  849. }
  850.  
  851. - setSambaLogging:sender
  852. {
  853.         return [self openFilePath:YES field:fieldsmbLogFile];
  854. }
  855.  
  856. - testParameters:sender
  857. {
  858. char    buf[4096];
  859. FILE    *pipe;
  860.  
  861.         if (![[NXBundle mainBundle] getPath:buf forResource:"testparm" ofType:NULL])
  862.                 if (![NXBundle getPath:buf forResource:"testparm" ofType:NULL
  863.                                              inDirectory:"/LocalLibrary/SambaManager" withVersion:0])
  864.                     if (![NXBundle getPath:buf forResource:"testparm" ofType:NULL
  865.                                                  inDirectory:"/LocalLibrary/SambaManager/samba" withVersion:0])
  866.                         if (![NXBundle getPath:buf forResource:"testparm" ofType:NULL
  867.                                                      inDirectory:"/users/local/samba/bin" withVersion:0])
  868.                             *buf = '\0';
  869.  
  870.         [textParameters setEditable:YES];
  871.         [textParameters selectText:self];
  872.         if (*buf) {
  873.             [textParameters replaceSel:""];
  874.             (void)strcat(buf,"\n\n");
  875.             pipe = popen(buf, "r");
  876.             while (fgets(buf, 4096, pipe)) {
  877.                 [textParameters setSel:[textParameters textLength] :[textParameters textLength]];
  878.                 [textParameters replaceSel:buf];
  879.             }
  880.             pclose(pipe);
  881.         } else {
  882.             [textParameters replaceSel:"Could not find the testparm program.\nLooked for it in:\n  the bundle\n  /LocalLibrary/SambaManager\n  /LocalLibrary/SambaManager/samba\n  /users/local/samba/bin"];
  883.         }
  884.         [textParameters setEditable:NO];
  885.  
  886.         [windowParameters makeKeyAndOrderFront:self];
  887.         return self;
  888. }
  889.  
  890. // ****************************************************
  891. // Delegates
  892.  
  893. -appDidInit:sender
  894. {
  895. id    menu;
  896. id    popup;
  897.  
  898.         // Allocate and initialize the lists of opened windows.
  899.         serviceList = [[List alloc] initCount:1];
  900.         offset = 0.0;
  901.         uid = getuid();
  902.         euid = geteuid();
  903.         rootOk = NO;
  904.  
  905.         // Set up the popups for the logging level
  906.         popup = [buttonSMBLogging target];
  907.         [popup setTarget:self];
  908.         [popup setAction:@selector(markEdited:)];
  909.         matrixSMBLogging = [popup itemList];
  910.         popup = [buttonSMBLogMethod target];
  911.         [popup setTarget:self];
  912.         [popup setAction:@selector(markEdited:)];
  913.         matrixSMBLogMethod = [popup itemList];
  914.         popup = [buttonNMBLogging target];
  915.         [popup setTarget:self];
  916.         [popup setAction:@selector(markEdited:)];
  917.         matrixNMBLogging = [popup itemList];
  918.  
  919.         // Scan the INETD.CONF file.
  920.         [self scanEtcInetdConf:0];
  921.         
  922.         // Set up menu enabling/disabling methods.
  923.         menu = [menuCellSamba target];
  924.         [menuDelete setUpdateAction:@selector(menuActive:) forMenu:menu];
  925.         [menuSave setUpdateAction:@selector(menuActive:) forMenu:menu];
  926.         [menuSaveToDomain setUpdateAction:@selector(menuActive:) forMenu:menu];
  927.         [menuRevert setUpdateAction:@selector(menuActive:) forMenu:menu];
  928.         [menuClose setUpdateAction:@selector(menuActive:) forMenu:menu];
  929.  
  930.         // Set up automatic menu enabling/disabling.
  931.         [NXApp setAutoupdate:YES];
  932.  
  933.         return self;
  934. }
  935.  
  936. -appWillTerminate:sender
  937. {
  938. int    i, elements = [serviceList count];
  939.  
  940.         if ([windowStartup isDocEdited] && (!uid || !euid)) {
  941.             i = NXRunAlertPanel([strings valueForStringKey:"Alert:Alert"],
  942.                                                     [strings valueForStringKey:"Message:Save changes to daemon startup?"],
  943.                                                     [strings valueForStringKey:"Button:Save"],
  944.                                                     [strings valueForStringKey:"Button:Don't Save"],
  945.                                                     [strings valueForStringKey:"Button:Cancel"]);
  946.             switch (i) {
  947.                 case NX_ALERTDEFAULT:
  948.                     if (![self setNetInfo])
  949.                         return nil;
  950.                 case NX_ALERTALTERNATE:
  951.                     break;
  952.                 default:
  953.                     return nil;
  954.             }
  955.         }
  956.         
  957.         for (i = 0; i < elements; i++)
  958.             if (![[serviceList objectAt:i] close:self])
  959.                 return nil;
  960.  
  961.         return self;
  962. }
  963.  
  964. - textDidGetKeys:sender isEmpty:(BOOL)flag
  965. {
  966.         return [self markEdited:self];
  967. }
  968.  
  969. - textDidEnd:textObject endChar:(unsigned short)whyEnd
  970. {
  971.         if (([textObject superview] == fieldPassword) && (whyEnd == NX_RETURN))
  972.             [NXApp stopModal];
  973.  
  974.         return self;
  975. }
  976.  
  977. @end
  978.