summaryrefslogtreecommitdiff
path: root/deleted_files
diff options
context:
space:
mode:
authorseb <none@none>2007-08-13 08:33:13 -0700
committerseb <none@none>2007-08-13 08:33:13 -0700
commit35076d53642115be972f548db8761effee923cf8 (patch)
treef9e11ecb9c2d9dd37d7f405de92e1c3cb91f0f5b /deleted_files
parentd577a05052763490983ba19d548a252fed6f75d9 (diff)
downloadillumos-gate-35076d53642115be972f548db8761effee923cf8.tar.gz
6479886 mipagent and related kernel interfaces should be removed (fix unref)
--HG-- rename : usr/src/cmd/cmd-inet/common/conflib.c => deleted_files/usr/src/cmd/cmd-inet/common/conflib.c rename : usr/src/cmd/cmd-inet/common/conflib.h => deleted_files/usr/src/cmd/cmd-inet/common/conflib.h
Diffstat (limited to 'deleted_files')
-rw-r--r--deleted_files/usr/src/cmd/cmd-inet/common/conflib.c2116
-rw-r--r--deleted_files/usr/src/cmd/cmd-inet/common/conflib.h122
2 files changed, 2238 insertions, 0 deletions
diff --git a/deleted_files/usr/src/cmd/cmd-inet/common/conflib.c b/deleted_files/usr/src/cmd/cmd-inet/common/conflib.c
new file mode 100644
index 0000000000..b2d4014adc
--- /dev/null
+++ b/deleted_files/usr/src/cmd/cmd-inet/common/conflib.c
@@ -0,0 +1,2116 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file implements windows style INI files. It caches
+ * files in memory, so they are not parsed on each read.
+ *
+ * WARNING: This library is completely UN-THREAD-SAFE and NON-REENTRANT.
+ */
+
+/* LINTLIBRARY */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <strings.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <net/pfkeyv2.h> /* ipsec alg, etc., values */
+#include <errno.h>
+
+#include "conflib.h"
+
+#define INI_MAX_CACHED 10 /* Maximum number of files to keep cached */
+#define MAX_LONG_LEN 20 /* The printed size of a 32 bit number */
+
+/* ********************* Internal Structures ******************** */
+
+/* This is the simplest part. A label. This is the atom of the ini file */
+typedef struct {
+ char Label[MAX_LABEL_LEN];
+ char Value[MAX_VALUE_LEN];
+} LabelType;
+
+/* A section contains an array list of labels */
+typedef struct {
+ int NumLabels;
+ char SectionName[MAX_FILENAME_LEN];
+ LabelType *Labels;
+} SectionType;
+
+/* An ini file contains an array list of Sections */
+typedef struct {
+ int NumSections;
+ char Filename[MAX_FILENAME_LEN];
+ time_t ModificationTime;
+ SectionType *Sections;
+} IniFileType;
+
+/* An IniFileList Contains a linked list of ini files */
+typedef struct s {
+ IniFileType IniFile;
+ struct s *Next;
+} IniFileList;
+
+static IniFileList *IniHead = NULL;
+
+#define BUF_LEN MAX_LABEL_LEN + MAX_VALUE_LEN
+#define INI_SECTION 1
+#define INI_LABEL 2
+#define INI_ERROR 0
+
+char ErrorString[ERROR_STRING_LEN];
+
+boolean_t encr_alg_set = FALSE; /* true if encr_alg set */
+
+/* These are the valid ipsec actions mipagent and friends support. */
+char *validIPsecAction[] = {
+ "apply", /* outbound IPsec Policy */
+ "permit", /* inbound IPsec Policy */
+ NULL
+};
+
+/* Each entry in our various ipsec algorithm tables is one of these */
+struct ipsec_alg {
+ char *alg;
+ uint_t value;
+};
+
+/* Some macroed values */
+#define NO_AH_AALG 256
+#define NO_ESP_AALG 256
+#define NO_ESP_EALG 256
+
+/* valid encr_algs to match with user config */
+struct ipsec_alg encr_algs[] = {
+ {"any", SADB_EALG_NONE},
+ {"des", SADB_EALG_DESCBC},
+ {"des-cbc", SADB_EALG_DESCBC},
+ {"3des", SADB_EALG_3DESCBC},
+ {"3des-cbc", SADB_EALG_3DESCBC},
+ {"blowfish", SADB_EALG_BLOWFISH},
+ {"blowfish-cbc", SADB_EALG_BLOWFISH},
+ {"aes", SADB_EALG_AES},
+ {"aes-cbc", SADB_EALG_AES},
+ {"null", SADB_EALG_NULL},
+ {"none", NO_ESP_EALG},
+ {NULL, 0}
+};
+
+/* one auth_algs to match with user configs */
+struct ipsec_alg auth_algs[] = {
+ {"any", SADB_AALG_NONE},
+ {"md5", SADB_AALG_MD5HMAC},
+ {"hmac-md5", SADB_AALG_MD5HMAC},
+ {"sha1", SADB_AALG_SHA1HMAC},
+ {"hmac-sha1", SADB_AALG_SHA1HMAC},
+ {"sha", SADB_AALG_SHA1HMAC},
+ {"hmac-sha", SADB_AALG_SHA1HMAC},
+ {"none", NO_AH_AALG},
+ {NULL, 0}
+};
+
+#define SADB_SA_SHARED 0
+#define SADB_SA_UNIQUE 1
+
+/*
+ * One for sa_algs. OK, these aren't algs, but in order to make the parsing
+ * of properties easy, they're laid out "<tag> <alg> <tag> <alg> ...", so it's
+ * designed so <tag> maps directly to the function that parses <alg>. The
+ * "... sa (shared | unique)" bit then needs to be done analogously.
+ */
+struct ipsec_alg sa_algs[] = {
+ {"shared", SADB_SA_SHARED},
+ {"unique", SADB_SA_UNIQUE},
+ {NULL, 0},
+};
+
+
+/*
+ * Internal prototypes
+ */
+static int IniLoadFile(char *Filename);
+static void InitializeIniFile(IniFileList *FileList);
+static int IniParseFile(IniFileType *File, char *Filename);
+static int AddSection(IniFileType *IniFile, char *Section);
+static int AddLabel(IniFileType *IniFile, int SectionNdx, char *Label,
+ char *Data);
+static void ModifyLabel(IniFileType *IniFile, int SectionNdx, int LabelNdx,
+ char *Data);
+static int IniCheckComment(char *buffer);
+static int ParseLine(char *buffer, char *TempLabel, char *TempValue);
+static int IniLoaded(char *Filename);
+static int IniUpdateLocalCopy(char *Filename, char *Section, char *Label,
+ char *Data);
+#ifndef lint /* this function is not used for now */
+static char *GetSectionList(IniFileType *IniFile, char *argv, int *NumSections,
+ int *elementSize);
+#endif /* lint */
+static IniFileList *UnlinkFile(char *Filename);
+static int IniUnloadFile(char *Filename);
+static int IniUpdateFile(char *Filename, char *Section, char *Label,
+ char *Data);
+static int CopyToSection(char *Section, FILE *in, FILE *out, int CopySection);
+static void CopyToEOF(FILE *in, FILE *out, char *Label);
+static char *dirname(char *FullPath);
+static void CheckAndAllocateCacheSpace();
+static void IniFreeFile(IniFileList *File);
+static int Rename(char *source, char *dest);
+static int GetSectionProfileString(IniFileList *IniFile, char *Section,
+ char *Label, char *dest, int destLen);
+static int GetLabelProfileString(IniFileList *IniFile, int SectionNdx,
+ char *Label, char *dest, int destLen);
+
+/* ipsec algorithm parsing routines */
+int parsealg(char *, struct ipsec_alg *);
+int parse_algs(int, int, ipsec_req_t *);
+int parse_esp_auth_alg(char *, ipsec_req_t *);
+int parse_esp_encr_alg(char *, ipsec_req_t *);
+int parse_ah_alg(char *, ipsec_req_t *);
+int parse_sa_alg(char *, ipsec_req_t *);
+uint_t isIPsecActionValid(char *);
+
+
+/* something to switch on */
+enum ipsec_alg_type { ESP_ENCR_ALG = 1, ESP_AUTH_ALG, AH_AUTH_ALG, SA_ALG };
+
+/* table for parsing IPSEC related algs */
+struct ipsec_cmd {
+ char *c_name;
+ int (*c_func)(char *, ipsec_req_t *);
+} ipseccmd[] = {
+ { "encr_auth_algs", parse_esp_auth_alg },
+ { "encr_algs", parse_esp_encr_alg },
+ { "auth_algs", parse_ah_alg },
+ { "sa", parse_sa_alg },
+ { 0, 0 },
+};
+
+
+/*
+ * Function: InitializeIniFile
+ *
+ * Arguments: IniFileList *
+ *
+ * Description: This function will Initialize an ini file
+ *
+ * Returns: void
+ *
+ */
+static void
+InitializeIniFile(IniFileList *New)
+{
+ New->Next = NULL;
+ New->IniFile.NumSections = 0;
+ (void) memset(New->IniFile.Filename, 0, MAX_FILENAME_LEN);
+ New->IniFile.ModificationTime = 0;
+ New->IniFile.Sections = NULL;
+} /* InitializeIniFile */
+
+/*
+ * Function: FileHasChanged
+ *
+ * Arguments: ModificationTime, Filename
+ *
+ * Description: This function will return true if the filename's
+ * modification time is different than the one passed in.
+ * It also returns true on error. If we aren't able to get a
+ * stat() of the file, just assume it has changed.
+ *
+ * Returns: int (non zero if time has changed)
+ *
+ */
+static int
+FileHasChanged(time_t ModificationTime, char *Filename)
+{
+ struct stat file_stats;
+
+ if (stat(Filename, &file_stats) == (-1)) {
+ char *errMsg = strerror(errno);
+
+ if (errno == ENOENT)
+ return (TRUE); /* file does not exist */
+
+ /*
+ * Some kind of error. Just return TRUE.
+ * Note: we come in here twice, once via IniLoaded(), and
+ * (if that fails) again from IniLoadFile(). It would be
+ * mostly innocuous to overwrite ErrorString with this [same]
+ * message, but why bother?
+ */
+ if (ErrorString[0] == '\0') {
+ snprintf(ErrorString, sizeof (ErrorString), "Warning: "
+ "unable to retrieve stats on <%s>. %s.", Filename,
+ errMsg != NULL ? errMsg : "Unknown error");
+ }
+
+ return (TRUE);
+ }
+
+ /*
+ * Now return the change state
+ */
+ return (ModificationTime != file_stats.st_mtime);
+} /* FileHasChanged */
+
+/*
+ * Function: IniLoadFile
+ *
+ * Arguments: Filename
+ *
+ * Description: This function loads in a configuration file.
+ * It caches files by moving them to the head of the linked
+ * list. It also checks for files that have changed on the disk
+ * by using stat().
+ *
+ * Returns: int (zero on success)
+ *
+ */
+static int
+IniLoadFile(char *Filename)
+{
+ IniFileList *NewIniFileNode, *Probe;
+ IniFileList *Last = NULL;
+
+ for (Probe = IniHead; Probe; Probe = Probe->Next) {
+ /* Check to see if it is already loaded */
+ if (strcmp(Probe->IniFile.Filename, Filename) == 0) {
+ /*
+ * Found it, we already have it cached.
+ * check Date/Time stamp
+ */
+ if (FileHasChanged(Probe->IniFile.
+ ModificationTime, Filename)) {
+ /* Reload the file */
+ (void) IniUnloadFile(Filename);
+ break; /* Leave loop */
+ } else {
+ /*
+ * It is our file, and it hasn't changed,
+ * Cache our entry by moving it to the head
+ * of the list and return success.
+ */
+ if (Last) {
+ /*
+ * Only move it if this is not the
+ * first entry.
+ */
+ Last->Next = Probe->Next;
+ Probe->Next = IniHead;
+ IniHead = Probe;
+ }
+ return (0);
+ }
+ } /* strcmp checking filename */
+ Last = Probe;
+ } /* For loop searching for file */
+
+ /*
+ * Now, we know that we don't have the file cached or loaded, so
+ * allocate memory and load it.
+ * Note: IniFileList is the bucket that holds a STATIC IniFileType.
+ */
+ NewIniFileNode = malloc(sizeof (IniFileList));
+ if (!NewIniFileNode) {
+ (void) strcpy(ErrorString,
+ "Unable to allocate memory for new ini file.");
+ return (-1);
+ }
+
+ /*
+ * Add it to our head. But first, remove the last entry if we have
+ * Too many items in our cache.
+ */
+ CheckAndAllocateCacheSpace();
+ NewIniFileNode->Next = IniHead;
+ IniHead = NewIniFileNode;
+
+ /*
+ * Now we have a pointer to New. Clear it, and parse in the
+ * new file
+ */
+ InitializeIniFile(NewIniFileNode);
+ if (IniParseFile(&NewIniFileNode->IniFile, Filename)) {
+ /* Remove ini file from list */
+ IniHead = NewIniFileNode->Next;
+ free(NewIniFileNode);
+ return (-2);
+ }
+
+ return (0);
+} /* IniLoadFile */
+
+/*
+ * Function: CheckAndAllocateCacheSpace
+ *
+ * Arguments: none
+ *
+ * Description: This routine will check to see if our INI cache is full, and
+ * if so, will delete the last (least recently used) entry.
+ *
+ * Returns: void
+ *
+ */
+static void
+CheckAndAllocateCacheSpace()
+{
+ IniFileList *Probe;
+ IniFileList *Last;
+ int count;
+
+ /* Return if the cache is empty (or nearly empty) */
+ if (!IniHead || !IniHead->Next)
+ return;
+
+ /*
+ * Send Probe to next to end of list, and last to one before probe,
+ * while counting with count.
+ */
+ for (Probe = IniHead, count = 0, Last = IniHead;
+ Probe->Next;
+ Probe = Probe->Next, count++)
+ Last = Probe;
+
+ if (count >= INI_MAX_CACHED) {
+ /* Our cache is full. Free the last entry */
+ Last->Next = NULL;
+ IniFreeFile(Probe);
+ }
+} /* CheckAndAllocateCacheSpace */
+
+/*
+ * Function: IniParseFile
+ *
+ * Arguments: IniFileType *File, char *Filename
+ *
+ * Description: This routine will parse the INI file and load the Section
+ * and Label arrays.
+ *
+ * Returns: int
+ */
+static int
+IniParseFile(IniFileType *File, char *Filename)
+{
+ int LineNo;
+ char CurrentSection[MAX_LABEL_LEN];
+ char buffer[BUF_LEN];
+ char TempLabel[MAX_LABEL_LEN], TempValue[MAX_VALUE_LEN];
+ FILE *handle;
+ int rc;
+ struct stat file_stat;
+
+ /*
+ * Copy the filename...
+ */
+ (void) strncpy(File->Filename, Filename, MAX_FILENAME_LEN);
+ File->Filename[MAX_FILENAME_LEN-1] = 0; /* Just in case we overran */
+
+ (void) memset(CurrentSection, 0, MAX_LABEL_LEN);
+
+ /* Set the modification time */
+ if (stat(Filename, &file_stat) == 0) {
+ File->ModificationTime = file_stat.st_mtime;
+ } else {
+ char *errMsg = strerror(errno);
+
+ (void) snprintf(ErrorString, sizeof (ErrorString),
+ "Unable to stat <%s>. %s.", Filename,
+ errMsg != NULL ? errMsg : "Unknown error");
+
+ return (-1);
+ }
+
+ /* Open the file */
+ handle = fopen(Filename, "rt");
+ if (handle == NULL) {
+ char *errMsg = strerror(errno);
+
+ (void) snprintf(ErrorString, sizeof (ErrorString),
+ "Unable to open file <%s>. %s.", Filename,
+ errMsg != NULL ? errMsg : "Unknown error");
+
+ return (-1);
+ }
+
+ LineNo = 0;
+ while (fgets(buffer, BUF_LEN, handle)) {
+ LineNo++;
+ /* If it is a comment or a blank line, don't process it */
+ if (IniCheckComment(buffer))
+ continue;
+
+ switch (ParseLine(buffer, TempLabel, TempValue)) {
+ case INI_SECTION:
+ /* Call our add section function */
+ rc = AddSection(File, TempLabel);
+ /* If an error occurs, AddSection sets ErrorString */
+ if (rc < 0) {
+ (void) fclose(handle);
+ return (rc);
+ }
+ break;
+
+ case INI_LABEL:
+ /*
+ * check to see if we are before our first
+ * section label
+ */
+ if (!File->NumSections) {
+ (void) sprintf(ErrorString, "Data outside of "
+ "section on line %d.", LineNo);
+ (void) fclose(handle);
+ return (-2);
+ }
+ rc = AddLabel(File, File->NumSections-1, TempLabel,
+ TempValue);
+ /* If an error occurs, AddLabel sets ErrorString */
+ if (rc < 0) {
+ (void) fclose(handle);
+ return (rc);
+ }
+ break;
+ case INI_ERROR:
+ default:
+ (void) snprintf(ErrorString, sizeof (ErrorString),
+ "Error parsing INI file (%s) on line %d.",
+ Filename, LineNo);
+ (void) fclose(handle);
+ return (-3);
+ }
+ }
+
+ /* Success! */
+ (void) fclose(handle);
+ return (0);
+} /* IniParseFile */
+
+/*
+ * Function: TrimWhiteSpace
+ *
+ * Arguments: char *buffer
+ *
+ * Description: This function removes leading and trailing white space
+ * from a string.
+ *
+ * Returns: static void
+ */
+static void
+TrimWhiteSpace(char *buffer)
+{
+ int i, j;
+ /* First, find first non-whitespace character */
+ for (i = 0; buffer[i] && isspace((int)buffer[i]); i++);
+
+ /*
+ * Now, i is pointing to the first non-white space
+ * character in buffer
+ */
+
+ /* Find the last non-whitespace character */
+ for (j = strlen(buffer)-1; j > 0 && isspace((int)buffer[j]); j--);
+
+ if ((i > j) || (j < 0)) {
+ /* Empty */
+ buffer[0] = 0;
+ } else {
+ /* copy the usable buffer */
+ bcopy(&buffer[i], buffer, (j-i)+1);
+ /* and Null-terminate it */
+ buffer[(j-i)+1] = 0;
+ }
+} /* TrimWhiteSpace */
+
+/*
+ * Function: ParseLine
+ *
+ * Arguments: char *buffer, char *TempTag, char *TempValue
+ *
+ * Description: This routine will return either the section or label
+ * information. If it finds a section line in the buffer,
+ * it will return the section name in the TempTag Field.
+ * If it finds a Label, it will fill out TempValue and
+ * TempTag.
+ *
+ * Returns: int
+ */
+static int
+ParseLine(char *staticBuffer, char *TempTag, char *TempValue)
+{
+ int i = 0, j = 0;
+ int EqualFound = FALSE;
+ char buffer[BUF_LEN];
+
+ (void) strlcpy(buffer, staticBuffer, BUF_LEN);
+
+ /* Trim the white space of the entire buffer first */
+ TrimWhiteSpace(buffer);
+
+ if (buffer[0] == '[') {
+ /* Must be a section */
+ for (i = 1; buffer[i] && buffer[i] != ']'; i++)
+ TempTag[j++] = buffer[i];
+
+ /* Check to make sure we got an end-bracket */
+ if (buffer[i] != ']')
+ /* Bad Section! */
+ return (INI_ERROR);
+
+ TempTag[j] = 0;
+ TrimWhiteSpace(TempTag);
+ return (INI_SECTION);
+ }
+ for (i = 0; buffer[i]; i++) {
+ if (buffer[i] == '=') {
+ EqualFound = TRUE;
+ TempTag[j] = 0;
+ j = 0;
+ } else {
+ if (!EqualFound)
+ TempTag[j++] = buffer[i];
+ else
+ TempValue[j++] = buffer[i];
+ }
+ }
+ if (!EqualFound) {
+ /* Bad Label! */
+ return (INI_ERROR);
+ }
+ TempValue[j] = 0;
+ /* Handle EOLN */
+ if (TempValue[j-1] == '\n')
+ TempValue[j-1] = 0;
+
+ /* And finally, trim the white space off of our return strings */
+ TrimWhiteSpace(TempTag);
+ TrimWhiteSpace(TempValue);
+ return (INI_LABEL);
+} /* ParseLine */
+
+
+/*
+ * Function: IniUpdateFile
+ *
+ * Arguments: char *Filename, char *Section, char *Label, char *Data
+ *
+ * Description: This will update our INI file. It copies the file from
+ * it's original position to a temp one, then renames to
+ * overwrite the original.
+ *
+ * Returns: int (zero on success)
+ */
+static int
+IniUpdateFile(char *Filename, char *Section, char *Label, char *Data)
+{
+ FILE *in, *out;
+ char TempFile[MAX_FILENAME_LEN];
+ int DeleteSection = 0;
+ int DeleteLabel = 0;
+
+ /* Set our deletion flags */
+ if (!Label && !Data)
+ DeleteSection = 1;
+
+ if (!Data)
+ DeleteLabel = 1;
+
+ /*
+ * Don't worry about checking the handle right away. It's checked
+ * later. If the input file open fails, we assume that the file just
+ * does not exist. It will be created when the output file is renamed
+ * into the input file (or it is copied).
+ */
+ in = fopen(Filename, "r+");
+
+ /* Create a temporary file name in the same directory as the INI file */
+ (void) strlcpy(TempFile, tempnam(dirname(Filename), NULL),
+ sizeof (TempFile));
+
+ out = fopen(TempFile, "w");
+ if (!out) {
+ char *errMsg = strerror(errno);
+
+ (void) snprintf(ErrorString, sizeof (ErrorString),
+ "Unable to copy <%s>, can't open temp file <%s>. %s.",
+ Filename, TempFile,
+ errMsg != NULL ? errMsg : "Unknown error");
+
+ (void) fclose(in);
+ return (-1);
+ }
+
+ if (in) {
+ /* Our input file exists */
+ if (!CopyToSection(Section, in, out, DeleteSection?0:1)) {
+ /*
+ * Section did not exist, make one
+ * If DeleteSection or DeleteLabel is set, it's a nop.
+ */
+
+ if (!DeleteSection && !DeleteLabel) {
+ (void) fprintf(out, "[%s]\n", Section);
+ (void) fprintf(out, "%s=%s\n", Label, Data);
+ }
+ } else {
+ if (DeleteSection) {
+ /*
+ * Delete the section.
+ * Copy to EOF with NULL as the label
+ */
+ CopyToEOF(in, out, NULL);
+ } else {
+ /*
+ * Section did exist, just dump label, and
+ * search for next section or same label line,
+ * so we can erase it.
+ */
+ if (!DeleteLabel) {
+ /*
+ * Dump the new label, only if
+ * we're not deleting it
+ */
+ (void) fprintf(out, "%s=%s\n",
+ Label, Data);
+ }
+ CopyToEOF(in, out, Label);
+ }
+ }
+ (void) fclose(in);
+ } else {
+ /* no input file, just put output */
+ (void) fprintf(out, "[%s]\n", Section);
+ (void) fprintf(out, "%s=%s\n", Label, Data);
+ }
+
+ (void) fclose(out);
+ /*
+ * The rename could file for many reasons, but all of them are very
+ * bad ones. Assume that Rename has set ErrorString.
+ */
+ if (Rename(TempFile, Filename)) {
+ return (-1);
+ }
+ /* Let our internal update set the return code now */
+ return (IniUpdateLocalCopy(Filename, Section, Label, Data));
+} /* IniUpdateFile */
+
+/*
+ * Function: Rename
+ *
+ * Arguments: char *source, char *dest
+ *
+ * Description: This function tries a rename. If it fails, it tries a copy.
+ * It should never fail, since the temp file is in the same
+ * directory as the input file.
+ *
+ * Returns: int (zero on success)
+ */
+int
+Rename(char *source, char *dest)
+{
+ int rc;
+ if ((rc = rename(source, dest)) != 0) {
+ /* Do copy! */
+ FILE *in, *out;
+ char buffer[BUFSIZ]; /* use the system BUFSIZ for efficiency */
+ int nchars;
+
+ in = fopen(source, "r");
+ if (!in) {
+ char *errMsg = strerror(errno);
+
+ (void) snprintf(ErrorString, sizeof (ErrorString),
+ "Error opening source file <%s> for rename. %s.",
+ source, errMsg != NULL ? errMsg : "Unknown error");
+
+ return (-1);
+ }
+ out = fopen(dest, "w");
+ if (!out) {
+ char *errMsg = strerror(errno);
+
+ (void) fclose(in);
+ (void) unlink(dest);
+ (void) snprintf(ErrorString, sizeof (ErrorString),
+ "Error opening target file <%s> for rename. %s.",
+ dest, errMsg != NULL ? errMsg : "Unknown error");
+
+ return (-2);
+ }
+
+ /* Ok, now do copy */
+ do {
+ nchars = fread(buffer, 1, BUFSIZ, in);
+ if (nchars > 0) {
+ rc = fwrite(buffer, 1, nchars, out);
+ if (rc != nchars) {
+ char *errMsg = strerror(errno);
+
+ (void) snprintf(ErrorString,
+ sizeof (ErrorString),
+ "Error writing target file <%s> "
+ "during rename. %s.", dest,
+ errMsg != NULL ? errMsg :
+ "Unknown error.");
+
+ (void) fclose(in);
+ (void) fclose(out);
+ (void) unlink(source);
+ return (rc);
+ }
+ }
+ } while (nchars > 0);
+
+ /* if fread() fails... */
+ if (nchars < 0) {
+ char *errMsg = strerror(errno);
+
+ (void) snprintf(ErrorString, sizeof (ErrorString),
+ "Error reading source file <%s>. %s.", source,
+ errMsg != NULL ? errMsg : "Unknown error");
+
+ (void) fclose(in);
+ (void) fclose(out);
+ (void) unlink(source);
+ return (nchars);
+ }
+
+ (void) fclose(in);
+ (void) fclose(out);
+ (void) unlink(source);
+ rc = nchars;
+ }
+
+ return (rc);
+} /* Rename */
+
+/*
+ * Function: dirname
+ *
+ * Arguments: char *FullPath
+ *
+ * Description: This function will return the directory name of the
+ * passed in filename. This is for out temporary file.
+ * the reason it is not in /tmp or /usr/tmp is that
+ * MV does not work across filesystems.
+ *
+ * Returns: char *
+ */
+static char *
+dirname(char *FullPath)
+{
+ int len;
+ static char Dirname[MAX_FILENAME_LEN * 8];
+
+ (void) strncpy(Dirname, FullPath, MAX_FILENAME_LEN * 8);
+ Dirname[MAX_FILENAME_LEN * 8 - 1] = 0;
+
+ for (len = strlen(Dirname); len; len--) {
+ if (Dirname[len] == '/') {
+ Dirname[len] = 0;
+ return (Dirname);
+ }
+ }
+ /*
+ * If we got here, then we searched the whole string, return NULL
+ */
+ return (NULL);
+} /* dirname */
+
+/*
+ * Function: RemoveSection
+ *
+ * Arguments: int SectionNdx, IniFileType *File
+ *
+ * Description: This function will remove a section from the given INI file.
+ * It does all the necessary garbage collection.
+ *
+ * Returns: int (zero on success)
+ */
+static int
+RemoveSection(int SectionNdx, IniFileType *File)
+{
+ /* First, remove all the labels */
+ if (File->Sections[SectionNdx].Labels)
+ free(File->Sections[SectionNdx].Labels);
+
+ /* Finally, remove the Section */
+ if (File->NumSections &&
+ (SectionNdx < File->NumSections) &&
+ SectionNdx >= 0) {
+ int NumToMove;
+ NumToMove = File->NumSections - SectionNdx -1;
+ /* Copy the rest down a notch */
+ if (NumToMove > 0) {
+ (void) memcpy(&File->Sections[SectionNdx],
+ &File->Sections[SectionNdx+1],
+ sizeof (SectionType) * NumToMove);
+ }
+ /* Free the last one */
+ File->NumSections--;
+ return (0);
+ } /* Sanity Check */
+ (void) snprintf(ErrorString, sizeof (ErrorString),
+ "Unable to remove section <%s> in INI file <%s>",
+ File->Sections->SectionName, File->Filename);
+ return (-1);
+} /*RemoveSection*/
+/*
+ * Function: RemoveLabel
+ *
+ * Arguments: SectionType *Section, int LabelNdx
+ *
+ * Description: This function will remove a label from the given INI
+ * file. (No GC is necessary, since the Arrays are Static)
+ *
+ * Returns: int
+ */
+static int
+RemoveLabel(SectionType *Section, int LabelNdx)
+{
+
+ /* Sanity Check */
+ if (Section->NumLabels &&
+ (LabelNdx < Section->NumLabels) &&
+ LabelNdx >= 0) {
+ int NumToMove;
+ NumToMove = Section->NumLabels - LabelNdx -1;
+ /* Copy the rest down a notch */
+ if (NumToMove > 0) {
+ (void) memcpy(&Section->Labels[LabelNdx],
+ &Section->Labels[LabelNdx+1],
+ sizeof (LabelType) * NumToMove);
+ }
+ /* Free the last one */
+ Section->NumLabels--;
+ return (0);
+ } /* Sanity Check */
+ (void) snprintf(ErrorString, sizeof (ErrorString),
+ "Unable to remove label <%s> from INI file ",
+ Section->Labels->Label);
+ return (-1);
+} /* RemoveLabel */
+
+/*
+ * Function: IniUpdateLocalCopy
+ *
+ * Arguments: char *Filename, char *Section, char *Label, char *Data
+ *
+ * Description: This function will update the internal copy of the data
+ * we have. (It is called form IniUpdateFile)
+ *
+ * Returns: int
+ */
+static int
+IniUpdateLocalCopy(char *Filename, char *Section, char *Label, char *Data)
+{
+ IniFileList *FileProbe;
+ IniFileType *File;
+ int SectionNdx, LabelNdx;
+ struct stat file_stats;
+ int DeleteSection = 0;
+ int DeleteLabel = 0;
+ int rc;
+
+ /* Set our deletion flags */
+ if (!Label && !Data)
+ DeleteSection = 1;
+
+ if (!Data)
+ DeleteLabel = 1;
+
+ /*
+ * First, search for the file
+ */
+ for (FileProbe = IniHead;
+ FileProbe;
+ FileProbe = FileProbe->Next) {
+ if (strcmp(FileProbe->IniFile.Filename,
+ Filename) == 0)
+ break;
+ }
+
+ if (!FileProbe) {
+ /*
+ * We did not find the file. Someone did a write without
+ * a read. Return an error. (The file is still written to,
+ * and the next read will parse it in.)
+ */
+ (void) sprintf(ErrorString, "Warning: file not loaded.");
+ return (0);
+ }
+ File = &FileProbe->IniFile;
+
+ /*
+ * Now let's update our statistics, so our cache is up to date.
+ */
+ if (stat(Filename, &file_stats) == (-1)) {
+ char *errMsg = strerror(errno);
+
+ (void) snprintf(ErrorString, sizeof (ErrorString),
+ "Error: Unable to retrieve statistics on <%s>. %s.",
+ Filename, errMsg != NULL ? errMsg : "Unknown error");
+
+ return (-2);
+ } else
+ File->ModificationTime = file_stats.st_mtime;
+
+ /*
+ * now, File contains our file pointer. Check
+ * to see if our section exists.
+ */
+ for (SectionNdx = 0; SectionNdx < File->NumSections; SectionNdx++) {
+ if (strcmp(Section,
+ File->Sections[SectionNdx].SectionName) == 0) {
+ /* We have the section! */
+ break;
+ }
+ }
+ if (SectionNdx >= File->NumSections) {
+ if (DeleteSection || DeleteLabel) {
+ (void) snprintf(ErrorString, sizeof (ErrorString),
+ "Error IniUpdateLocalCopy: "
+ "Section not found in <%s>",
+ Filename);
+ return (-1); /* Error, not found */
+ }
+
+ /* Oops New Section/Label! */
+ SectionNdx = AddSection(File, Section);
+ if (SectionNdx < 0)
+ return (SectionNdx);
+ (void) AddLabel(File, SectionNdx, Label, Data);
+ } else {
+ if (DeleteSection) {
+ return (RemoveSection(SectionNdx, File));
+ }
+ /* We have the section. Search for the label */
+ for (LabelNdx = 0;
+ LabelNdx < File->Sections[SectionNdx].NumLabels;
+ LabelNdx++) {
+ if (strcasecmp(Label,
+ File->Sections[SectionNdx].Labels[LabelNdx].Label)
+ == 0) {
+ if (DeleteLabel) {
+ return (RemoveLabel(
+ &File->Sections[SectionNdx],
+ LabelNdx));
+ }
+
+ /* Found the label. Update the data */
+ ModifyLabel(File, SectionNdx, LabelNdx, Data);
+ break;
+ }
+ }
+ if (LabelNdx >= File->Sections[SectionNdx].NumLabels) {
+ if (DeleteLabel) {
+ (void) snprintf(ErrorString,
+ sizeof (ErrorString),
+ "Error IniUpdateLocalCopy: "
+ "Label not found in <%s>",
+ Filename);
+ return (-1); /* Error, not found */
+ }
+ /* Need to add a label! */
+ rc = AddLabel(File, SectionNdx, Label, Data);
+ if (rc < 0)
+ return (rc);
+ }
+ }
+ return (0);
+} /* IniUpdateLocalCopy */
+
+/*
+ * Function: AddSection
+ *
+ * Arguments: IniFileType *IniFile, char *Section
+ *
+ * Description: This function will add a section to the passed in file.
+ *
+ * Returns: int
+ */
+static int
+AddSection(IniFileType *IniFile, char *Section)
+{
+ SectionType *SectionPointer;
+
+ /*
+ * Set up new section Array
+ */
+ SectionPointer = malloc(sizeof (SectionType) *
+ (IniFile->NumSections + 1));
+ if (!SectionPointer) {
+ (void) strcpy(ErrorString, "Out of memory allocating section.");
+ return (-1);
+ }
+ /*
+ * Copy old sections over - including pointers
+ */
+ if (IniFile->NumSections) {
+ (void) memcpy(SectionPointer, IniFile->Sections,
+ IniFile->NumSections * sizeof (SectionType));
+ free(IniFile->Sections); /* Free the old sections Array */
+ }
+ /*
+ * Update new section
+ */
+ (void) memset(SectionPointer[IniFile->NumSections].SectionName, '0',
+ MAX_FILENAME_LEN);
+ (void) strncpy(SectionPointer[IniFile->NumSections].SectionName,
+ Section,
+ MAX_SECTION_LEN);
+ SectionPointer[
+ IniFile->NumSections].SectionName[MAX_SECTION_LEN - 1] = 0;
+ SectionPointer[IniFile->NumSections].Labels = NULL;
+ SectionPointer[IniFile->NumSections].NumLabels = 0;
+
+ IniFile->NumSections++;
+ IniFile->Sections = SectionPointer; /* Update array pointer */
+
+ /* Return an index to the newly added one */
+ return (IniFile->NumSections-1);
+} /* AddSection */
+
+/*
+ * Function: AddLabel
+ *
+ * Arguments: IniFileType *IniFile, int SectionNdx, char *Label, char *Data
+ *
+ * Description: This function adds a label to a section.
+ *
+ * Returns: static int
+ */
+static int
+AddLabel(IniFileType *IniFile, int SectionNdx, char *Label, char *Data)
+{
+ SectionType *SectionPointer;
+ LabelType *LabelPointer;
+
+ /*
+ * Set up CurrentSection pointer for ease of typing.
+ */
+ SectionPointer = &IniFile->Sections[SectionNdx];
+
+ /*
+ * Allocate enough room for new label
+ */
+ LabelPointer = malloc(sizeof (LabelType) *
+ (SectionPointer->NumLabels+1));
+ if (!LabelPointer) {
+ (void) strcpy(ErrorString, "Out of memory allocating label.");
+ return (-3);
+ }
+ if (SectionPointer->NumLabels) {
+ /* Do the copy */
+ (void) memcpy(LabelPointer, SectionPointer->Labels,
+ sizeof (LabelType) * SectionPointer->NumLabels);
+ free(SectionPointer->Labels);
+ }
+
+ (void) memset(LabelPointer[SectionPointer->NumLabels].Label, 0,
+ MAX_LABEL_LEN);
+ (void) memset(LabelPointer[SectionPointer->NumLabels].Value, 0,
+ MAX_VALUE_LEN);
+ (void) strlcpy(LabelPointer[SectionPointer->NumLabels].Label,
+ Label, MAX_LABEL_LEN);
+ (void) strlcpy(LabelPointer[SectionPointer->NumLabels].Value,
+ Data, MAX_VALUE_LEN);
+
+ SectionPointer->NumLabels++;
+ SectionPointer->Labels = LabelPointer;
+
+ /* return the index of the new label */
+ return (SectionPointer->NumLabels-1);
+} /* AddLabel */
+
+/*
+ * Function: ModifyLabel
+ *
+ * Arguments: IniFileType *IniFile, int SectionNdx, int LabelNdx, char *Data
+ *
+ * Description: This function will just modify the data of a label in memory.
+ *
+ * Returns: void
+ */
+static void
+ModifyLabel(IniFileType *IniFile, int SectionNdx, int LabelNdx, char *Data)
+{
+ (void) memset(IniFile->Sections[SectionNdx].Labels[LabelNdx].Value,
+ 0, MAX_VALUE_LEN);
+ (void) strlcpy(IniFile->Sections[SectionNdx].Labels[LabelNdx].Value,
+ Data, MAX_VALUE_LEN);
+} /* ModifyLabel */
+
+/*
+ * Function: SectionCmp
+ *
+ * Arguments: char *line, char *Section
+ *
+ * Description: This function returns zero if the line is a section line,
+ * and contains our section.
+ *
+ * Returns: int
+ */
+static int
+SectionCmp(char *line, char *Section)
+{
+ char TempLabel[MAX_LABEL_LEN], TempValue[MAX_LABEL_LEN];
+
+ switch (ParseLine(line, TempLabel, TempValue)) {
+ case INI_SECTION:
+ return (strcmp(Section, TempLabel));
+ default: /* Not a section */
+ return (-1);
+ }
+
+} /* SectionCmp */
+
+/*
+ * Function: CopyToSection
+ *
+ * Arguments: char *Section, FILE *in, FILE *out, int CopySection
+ *
+ * Description: Copies the files from in to out, until it gets to
+ * the namedSection. If CopySection is non-zero, it
+ * will also copy the section line. If it is zero
+ * the section line will not be copied (for deletion)
+ *
+ * Returns: int (non-zero if the section was found)
+ */
+static int
+CopyToSection(char *Section, FILE *in, FILE *out, int CopySection)
+{
+ char tempbuffer[MAX_VALUE_LEN + MAX_LABEL_LEN];
+
+ while (fgets(tempbuffer, MAX_VALUE_LEN + MAX_LABEL_LEN, in)) {
+ if (!(SectionCmp(tempbuffer, Section))) {
+ /* We have the section */
+ if (CopySection)
+ (void) fputs(tempbuffer, out);
+
+ return (TRUE);
+ }
+ (void) fputs(tempbuffer, out);
+ }
+
+ return (FALSE);
+} /* CopyToSection */
+
+/*
+ * Function: CopyToEOF
+ *
+ * Arguments: FILE *in, FILE *out, char *Label
+ *
+ * Description: Copies from *in to *out, deleting Label in the current
+ * section. If Lable is NULL, then all labels are deleted until
+ * the next section is reached.
+ *
+ * Returns: void
+ */
+static void
+CopyToEOF(FILE *in, FILE *out, char *Label)
+{
+ char tempbuffer[BUF_LEN];
+ int SectionFound = FALSE;
+ char TempLabel[MAX_LABEL_LEN];
+ char TempValue[MAX_VALUE_LEN];
+
+
+ while (fgets(tempbuffer, BUF_LEN - 1, in)) {
+ if (!SectionFound) {
+ switch (ParseLine(tempbuffer, TempLabel, TempValue)) {
+ case INI_SECTION:
+ (void) fputs(tempbuffer, out);
+ SectionFound = TRUE;
+ break;
+ case INI_LABEL:
+ if (Label) {
+ /*
+ * If label is non-null, then copy
+ * everything EXCEPT the given label.
+ */
+ if (strcasecmp(Label, TempLabel)) {
+ (void) fputs(tempbuffer, out);
+ }
+ }
+ break;
+ default:
+ (void) fputs(tempbuffer, out);
+ break;
+ }
+ } else {
+ /*
+ * If the next section has been found,
+ * just write everything
+ */
+ (void) fputs(tempbuffer, out);
+ } /* if SectionFound */
+ } /* end While */
+} /* CopyToEOF */
+
+
+/*
+ * Function: GetSectionList
+ *
+ * Arguments: IniFileType *IniFile, char *argv, int *NumSections,
+ * int *elementSize
+ *
+ * Description: This routine returns a list of sections in a newly
+ * allocated array.
+ *
+ * Returns: char *, and modifies NumSections and elementSize
+ */
+static char *
+GetSectionList(IniFileType *IniFile, char *argv, int *NumSections,
+ int *elementSize)
+{
+ int i;
+
+ /*
+ * Do garbage collection
+ */
+ if (argv) {
+ free(argv);
+ }
+ argv = NULL;
+
+ if (!IniFile->NumSections)
+ return (argv);
+
+ argv = calloc(1, IniFile->NumSections*MAX_FILENAME_LEN);
+ if (!argv) {
+ (void) sprintf(ErrorString,
+ "Out of memory getting section list.");
+
+ return (NULL);
+ }
+ for (i = 0; i < IniFile->NumSections; i++) {
+ (void) strlcpy(&argv[i*MAX_FILENAME_LEN],
+ IniFile->Sections[i].SectionName,
+ MAX_FILENAME_LEN);
+ }
+ *NumSections = IniFile->NumSections;
+ *elementSize = MAX_FILENAME_LEN;
+ return (argv);
+} /* GetSectionList */
+
+/*
+ * Function: IniLoaded
+ *
+ * Arguments: char *Filename
+ *
+ * Description: Returns true if the specified file is loaded and has
+ * not changed.
+ *
+ * Returns: int
+ */
+static int
+IniLoaded(char *Filename)
+{
+ IniFileList *Probe;
+
+ for (Probe = IniHead; Probe; Probe = Probe->Next) {
+ if (strcmp(Filename, Probe->IniFile. Filename) == 0) {
+ if (FileHasChanged(Probe->IniFile.ModificationTime,
+ Filename)) {
+ return (FALSE);
+ } else {
+ return (TRUE);
+ }
+ }
+ }
+ return (FALSE);
+} /* IniLoaded */
+
+
+/*
+ * Function: IniCheckComment
+ *
+ * Arguments: char *buffer
+ *
+ * Description: Returns true if the given line is a comment, or if it is
+ * blank. Also removes any partial-line comments by
+ * replacing the semi-colon with a NULL;
+ *
+ * A comment is of the form :
+ * ; comment
+ * or
+ * # comment
+ *
+ * Returns: int
+ */
+static int
+IniCheckComment(char *buffer)
+{
+ int i;
+
+ for (i = 0; buffer[i] && (buffer[i] != '\n'); i++) {
+ if (buffer[i] == ';' || buffer[i] == '#') {
+ if (i) {
+ /* check for \; or \# */
+ if (buffer[i-1] == '\\')
+ continue;
+ }
+ /*
+ * Otherwise, mark it as a null, and check for an
+ * empty string
+ */
+ buffer[i] = 0;
+ break;
+ }
+ }
+
+ for (i = 0; buffer[i] && (buffer[i] != '\n'); i++) {
+ if (!isspace(buffer[i]))
+ return (0);
+ }
+
+ return (1); /* This is a blank (or commented) line */
+} /* IniCheckComment */
+
+/*
+ * Function: IniUnloadFile
+ *
+ * Arguments: char *Filename
+ *
+ * Description: This routine will remove an ini file from our list,
+ * and free up memory.
+ *
+ * Returns: int (zero on success)
+ */
+static int
+IniUnloadFile(char *Filename)
+{
+ IniFileList *File;
+
+ File = UnlinkFile(Filename);
+ if (!File)
+ return (-1);
+ IniFreeFile(File);
+ return (0);
+} /* IniUnloadFile */
+
+/*
+ * Function: IniFreeFile
+ *
+ * Arguments: IniFileList *File
+ *
+ * Description: Does the garbage collection on a file. (frees all data)
+ *
+ * Returns: void
+ */
+static void
+IniFreeFile(IniFileList *File)
+{
+ int CurrentSection;
+
+ /*
+ * Now, free up all the memory
+ */
+ for (CurrentSection = 0; CurrentSection < File->IniFile.NumSections;
+ CurrentSection++) {
+ /*
+ * Free up label array
+ */
+ if (File->IniFile.Sections[CurrentSection].Labels)
+ free(File->IniFile.Sections[CurrentSection].Labels);
+ }
+
+ /* Now free up the sections */
+ if (File->IniFile.Sections)
+ free(File->IniFile.Sections);
+
+ /* and finally... */
+ free(File);
+
+} /* IniFreeFile */
+
+/*
+ * Function: UnlinkFile
+ *
+ * Arguments: char *Filename
+ *
+ * Description: This routine will remove the file from the linked list, and
+ * return a pointer to it, so it can be freed.
+ *
+ * Returns: IniFileList *
+ */
+static IniFileList *
+UnlinkFile(char *Filename)
+{
+ IniFileList *Probe;
+ IniFileList *PrevProbe = NULL;
+
+ for (Probe = IniHead; Probe; Probe = Probe->Next) {
+ if (strcmp(Filename, Probe->IniFile.Filename) == 0) {
+ if (!PrevProbe) {
+ IniHead = Probe->Next;
+ } else {
+ PrevProbe->Next = Probe->Next;
+ }
+ return (Probe);
+ }
+ PrevProbe = Probe;
+ }
+ return (NULL);
+} /* UnlinkFile */
+
+/*
+ * Function: GetSectionProfileString
+ *
+ * Arguments: char *Section, char *Label, dest, destLen
+ *
+ * Description: This function is part of GetPrivateProfileString. It was
+ * Only Added to improve the C-Style formatting. (Fors got
+ * nested too deep.)
+ *
+ * Returns: static int
+ */
+static int
+GetSectionProfileString(IniFileList *IniFile, char *Section, char *Label,
+ char *dest, int destLen)
+{
+ int i;
+
+ /* We have the file */
+ for (i = 0; i < IniFile->IniFile.NumSections; i++) {
+ if (strcasecmp(Section,
+ IniFile->IniFile.Sections[i].SectionName)
+ == 0) {
+ return (GetLabelProfileString(IniFile,
+ i, Label, dest, destLen));
+ }
+ } /* end section for */
+
+ (void) snprintf(ErrorString, sizeof (ErrorString),
+ "Unable to find section <%s>.", Section);
+
+ return (-1);
+} /* GetSectionProfileString */
+
+/*
+ * Function: GetLabelProfileString
+ *
+ * Arguments: char *Section, char *Label, char *dest, int destLen
+ *
+ * Description: This function is part of GetPrivateProfileString. It was
+ * Only Added to improve the C-Style formatting. (Fors got
+ * nested too deep.)
+ *
+ * Returns: static int
+ */
+static int
+GetLabelProfileString(IniFileList *IniFile, int si, char *Label,
+ char *dest, int destLen)
+{
+ int j;
+
+ /* We have the section */
+ for (j = 0;
+ j < IniFile->IniFile.Sections[si].NumLabels;
+ j++) {
+ if (strcasecmp(Label,
+ IniFile->IniFile.Sections[si].Labels[j].Label) == 0) {
+ /* We finally have it! */
+ (void) strncpy(dest,
+ IniFile->IniFile.Sections[si].Labels[j].Value,
+ destLen);
+ return (0);
+ }
+ } /* end label for */
+
+ (void) snprintf(ErrorString, sizeof (ErrorString),
+ "Unable to find label <%s>.", Label);
+
+ return (-1);
+} /* GetLabelProfileString */
+
+/*
+ *
+ * E X T E R N A L F U N C T I O N S
+ *
+ * These functions are called by external programs. (They are non-static)
+ *
+ */
+
+
+
+/*
+ * Function: WritePrivateProfileString
+ *
+ * Arguments: char *Section, char *Label, char *data
+ *
+ * Description: Sets the new string into [Section] Label=data
+ *
+ * Returns: int (zero on success)
+ */
+int
+WritePrivateProfileString(char *Section, char *Label, char *data,
+ char *Filename)
+{
+ /*
+ * Unload the file, if it is loaded. The next read will load it.
+ */
+
+ return (IniUpdateFile(Filename, Section, Label, data));
+} /* WritePrivateProfileString */
+
+/*
+ * Function: DeletePrivateProfileSection
+ *
+ * Arguments: char *Section, char *Filename
+ *
+ * Description: Deletes an entire section (and all labels)
+ *
+ * Returns: int (zero on success)
+ */
+int
+DeletePrivateProfileSection(char *Section, char *Filename)
+{
+ return (IniUpdateFile(Filename, Section, NULL, NULL));
+} /* DeletePrivateProfileSection*/
+
+/*
+ * Function: DeletePrivateProfileLabel
+ *
+ * Arguments: char *Section, char *Label, char *Filename
+ *
+ * Description: Deletes a label from a section.
+ *
+ * Returns: int (zero on success)
+ */
+int
+DeletePrivateProfileLabel(char *Section, char *Label, char *Filename)
+{
+ return (IniUpdateFile(Filename, Section, Label, NULL));
+} /* DeletePrivateProfileLabel */
+
+/*
+ * Function: WritePrivateProfileInt
+ *
+ * Arguments: char *Section, char *Label, int data, char *Filename
+ *
+ * Description: Sets the new int into [Section] Label=data
+ *
+ * Returns: int (zero on success)
+ */
+int
+WritePrivateProfileInt(char *Section, char *Label, int data, char *Filename)
+{
+ char Tempbuffer[MAX_LONG_LEN]; /* we only need 10 + a negative sign */
+
+ (void) sprintf(Tempbuffer, "%d", data);
+ return (IniUpdateFile(Filename, Section, Label, Tempbuffer));
+} /* WritePrivateProfileInt */
+
+/*
+ * Function: GetPrivateProfileString
+ *
+ * Arguments: char *Section, char *Label, char *defaultValue
+ *
+ * Description: retrieves data from a section
+ *
+ * Returns: int (zero on success)
+ */
+int
+GetPrivateProfileString(char *Section, char *Label, char *defaultValue,
+ char *dest, int destLen, char *Filename)
+{
+ IniFileList *IniFile;
+ char errMsg[ERROR_SUBSTRING_LEN];
+ int rc;
+
+ /*
+ * First, Lookup the file, then lookup the section,
+ * then lookup the label, then copy the string
+ */
+
+ ErrorString[0] = 0; /* Clear the error string */
+
+ /* set default value */
+ (void) strlcpy(dest, defaultValue, destLen);
+
+ if (!IniLoaded(Filename)) {
+ rc = IniLoadFile(Filename);
+ if (rc < 0) {
+ return (rc);
+ }
+ }
+
+ for (IniFile = IniHead; IniFile; IniFile = IniFile->Next) {
+ if (strcmp(Filename, IniFile->IniFile.Filename) == 0)
+ return (GetSectionProfileString(IniFile, Section,
+ Label, dest, destLen));
+ } /* end file for */
+
+ /*
+ * IniLoaded() and IniLoadFile() call FileHasChanged() which may have
+ * something to say via ErrorString - don't overwrite it!
+ */
+ (void) snprintf(errMsg, ERROR_SUBSTRING_LEN,
+ "Unable to find file <%s>. ", Filename);
+
+ strlcat(ErrorString, errMsg, sizeof (ErrorString));
+
+ return (-1);
+} /* GetPrivateProfileString */
+
+/*
+ * Function: GetPrivateProfileInt
+ *
+ * Arguments: char *Section, char *Label, int defaultValue
+ *
+ * Description: Returns the int associated with [Section], Label=Int
+ *
+ * Returns: int
+ */
+int
+GetPrivateProfileInt(char *Section, char *Label, int defaultValue,
+ char *Filename)
+{
+ char String[MAX_LONG_LEN];
+
+ (void) GetPrivateProfileString(Section, Label, "", String,
+ MAX_LONG_LEN, Filename);
+
+ if (!String[0]) /* Our default return value is "" */
+ return (defaultValue);
+ else
+ return (atoi(String));
+} /* GetPrivateProfileInt */
+
+/*
+ * Function: IniListSections
+ *
+ * Arguments: char *Filename, int *NumSections, int *elementSize
+ *
+ * Description: Returns a list of sections. (allocates an array)
+ *
+ * Returns: char *
+ */
+char *
+IniListSections(char *Filename, int *NumSections, int *elementSize)
+{
+ static char *argv = NULL;
+ IniFileList *IniFile;
+ char errMsg[ERROR_SUBSTRING_LEN];
+ int rc;
+
+ if (!IniLoaded(Filename)) {
+ rc = IniLoadFile(Filename);
+ if (rc < 0) {
+ return (NULL);
+ }
+ }
+ for (IniFile = IniHead; IniFile; IniFile = IniFile->Next) {
+ if (strcmp(Filename, IniFile->IniFile.Filename) == 0) {
+ argv = GetSectionList(&IniFile->IniFile, argv,
+ NumSections, elementSize);
+ return (argv);
+ }
+ }
+
+ /*
+ * IniLoaded() and IniLoadFile() call FileHasChanged() which may have
+ * something to say via ErrorString - don't overwrite it!
+ */
+ (void) snprintf(errMsg, sizeof (ErrorString),
+ "Unable to find file <%s>. ", Filename);
+
+ strlcat(ErrorString, errMsg, sizeof (ErrorString));
+
+ return (NULL);
+} /* IniListSections */
+
+
+/*
+ * Function: parsealg
+ *
+ * Arguments: char *algname, struct ipsec_alg *table
+ *
+ * Description: finds the ipsec algorithm value associated with the ipsec
+ * algorithm string.
+ *
+ * Returns: valid alg value on success, -1 on failure.
+ */
+int
+parsealg(char *algname, struct ipsec_alg *table)
+{
+ struct ipsec_alg *ep;
+
+ if ((algname == NULL) || (table == NULL))
+ return (-1);
+
+ for (ep = table; ep->alg != NULL; ep++) {
+ if (strcasecmp(ep->alg, algname) == 0)
+ return (ep->value);
+ }
+
+ /* no match */
+ return (-1);
+}
+
+
+/*
+ * Function: parse_algs
+ *
+ * Arguments: int which_alg, int alg, ipsec_req_t *ipsr
+ *
+ * Description: sets the values in the ipsec_req_t passed in based on
+ * the algorithm, and which protection scheme it belongs to (ah_auth,
+ * esp_auth, or esp_encr. SA is also passed through here as a sanity
+ * check measure, and because of the way the parsing routines are
+ * designed - the user specifies all this as part of a the properties
+ * of a single IPsec policy.
+ *
+ * Returns: valid alg value on success, -1 on failure.
+ */
+int
+parse_algs(int which_alg, int alg, ipsec_req_t *ipsr)
+{
+ if (alg == -1)
+ /* alg is bad */
+ return (-1);
+
+ if (ipsr == NULL)
+ /* user didn't pass a pointer to set, alg is valid, OK */
+ return (0);
+
+ switch (which_alg) {
+ case ESP_ENCR_ALG:
+ if (alg == NO_ESP_AALG) {
+ if (ipsr->ipsr_esp_auth_alg == SADB_AALG_NONE)
+ ipsr->ipsr_esp_req = 0;
+ ipsr->ipsr_esp_alg = SADB_EALG_NONE;
+ } else {
+ ipsr->ipsr_esp_req =
+ IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE;
+ ipsr->ipsr_esp_alg = alg;
+ }
+ break;
+
+ case ESP_AUTH_ALG:
+ if (alg == NO_ESP_AALG) {
+ if (ipsr->ipsr_esp_alg == SADB_EALG_NONE ||
+ ipsr->ipsr_esp_alg == SADB_EALG_NULL)
+ ipsr->ipsr_esp_req = 0;
+ ipsr->ipsr_esp_auth_alg = SADB_AALG_NONE;
+ } else {
+ ipsr->ipsr_esp_req =
+ IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE;
+ ipsr->ipsr_esp_auth_alg = alg;
+
+ /* Let the user specify NULL encryption implicitly. */
+ if (ipsr->ipsr_esp_alg == SADB_EALG_NONE &&
+ !encr_alg_set)
+ ipsr->ipsr_esp_alg = SADB_EALG_NONE;
+ }
+ break;
+
+ case AH_AUTH_ALG:
+ if (alg == NO_AH_AALG) {
+ ipsr->ipsr_ah_req = 0;
+ ipsr->ipsr_auth_alg = SADB_AALG_NONE;
+ } else {
+ ipsr->ipsr_ah_req =
+ IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE;
+ ipsr->ipsr_auth_alg = alg;
+ }
+ break;
+
+ case SA_ALG:
+ if ((alg != SADB_SA_SHARED) &&
+ (alg != SADB_SA_UNIQUE))
+ return (-1);
+ break;
+
+ default:
+ /* don't know what to do! Fail. */
+ return (-1);
+ }
+ return (0);
+}
+
+/* ipsec algorithm parsing routines */
+int
+parse_esp_encr_alg(char *which_alg, ipsec_req_t *ipsr)
+{
+ return (parse_algs(ESP_ENCR_ALG, parsealg(which_alg, encr_algs), ipsr));
+}
+
+int
+parse_esp_auth_alg(char *which_alg, ipsec_req_t *ipsr)
+{
+ return (parse_algs(ESP_AUTH_ALG, parsealg(which_alg, auth_algs), ipsr));
+}
+
+int
+parse_ah_alg(char *which_alg, ipsec_req_t *ipsr)
+{
+ return (parse_algs(AH_AUTH_ALG, parsealg(which_alg, auth_algs), ipsr));
+}
+
+int
+parse_sa_alg(char *which_alg, ipsec_req_t *ipsr)
+{
+ return (parse_algs(SA_ALG, parsealg(which_alg, sa_algs), ipsr));
+}
+
+
+/*
+ * Function: isIPsecActionValid
+ *
+ * Parameters: action - the string containing the action in question.
+ *
+ * Description: Verifies the action is a valid ipsec action. Note that this
+ * function is NOT tollerant to leading whitespace!
+ *
+ * Returns: 0 on failure.
+ * strlen of the action on success (so the caller can index past it).
+ */
+uint_t
+isIPsecActionValid(char *action)
+{
+ int i;
+ char *cp = action;
+
+ for (i = 0; validIPsecAction[i] != NULL; i++) {
+ /* match check */
+ if (strncasecmp(cp, validIPsecAction[i],
+ strlen(validIPsecAction[i])) == 0)
+ return (strlen(validIPsecAction[i]));
+
+ /* try the next action */
+ }
+
+ return (0);
+}
+
+/*
+ * Function: parseIPsecProps
+ *
+ * Parameters: props - the string containing "{<props>}" for validation.
+ * ipsr - place to put parsed policy, NULL if not required.
+ * In this case parseIPsecProps() just tests to see
+ * if props are valid.
+ *
+ * Description: Verify properties are valid, and if so, put their values
+ * in the struct ipsec_req_t passed in. Valid properties are
+ * of the form "<tag> <alg>". Supported <tags> are in ipseccmd[],
+ * and the corresponding algs are in auth_algs[], and encr_algs[].
+ * Note: this function is tollerant to properties begining with
+ * blank spaces, but an open bracket MUST preceed <tag><alg>.
+ *
+ * Returns: 0 on failure in which case the values in ipsr are incomplete.
+ * number of bytes parsed on success in which case the values in ipsr,
+ * if passed in, are complete.
+ */
+int
+parseIPsecProps(char *props, ipsec_req_t *ipsr)
+{
+ struct ipsec_cmd *cmd;
+ char *p, *freeP, *deltaP = 0, *lasts;
+ int bytes_parsed = 0, ioff = 0, ret;
+ boolean_t bopen_found = _B_FALSE, bclose_found = _B_FALSE;
+
+ p = strdup(props);
+
+ if (p == NULL)
+ return (0);
+
+ freeP = p; /* strtok_r() is destructive */
+
+ while ((p = strtok_r(p, " ", &lasts)) != NULL) {
+ /*
+ * What did strtok_r() return if we have " { <properties..."?
+ * Skip white-space in general. ^^^
+ */
+ if ((*p != '\0') && (isspace(*p))) {
+ deltaP = p + strlen(p);
+ p = NULL;
+ continue;
+ }
+
+ if (!bopen_found) {
+ /* Every property begins with an open-bracket */
+ if (*p != '{') {
+ free(freeP);
+ return (0);
+ }
+ bopen_found = _B_TRUE;
+ /* move on */
+ p++;
+ }
+
+ if (*p == '}') {
+ /* this means we should be done */
+ if ((!bopen_found) || (bclose_found)) {
+ free(freeP);
+ return (0);
+ }
+
+ bclose_found = _B_TRUE;
+
+ deltaP = p + strlen(p);
+
+ p = NULL;
+ continue;
+ }
+
+ if (bclose_found) {
+ /* Stuff after the close! */
+ free(freeP);
+ return (0);
+ }
+
+ /* once for each <tag> the user wants set */
+ for (cmd = ipseccmd; cmd->c_func != NULL; cmd++) {
+ /* valid <tag>? */
+ if ((cmd->c_name) &&
+ (strcasecmp(cmd->c_name, p) == 0)) {
+ /* <alg> follows <tag>> */
+ p = NULL;
+ p = strtok_r(p, " ", &lasts);
+
+ if (p == NULL) {
+ /* nothing follows <tag> = error */
+ free(freeP);
+ return (0);
+ }
+
+ /* last <alg> may have a "}" at the end */
+ if (strcmp(&p[strlen(p)-1], "}") == 0) {
+ if (bclose_found) {
+ /* already found one = fail */
+ free(freeP);
+ return (0);
+ }
+ bclose_found = _B_TRUE;
+
+ /* char shortcuts are cool */
+ p[strlen(p)-1] = NULL;
+ ioff = 1;
+ }
+
+ /*
+ * Call the parse command for this <alg>, but
+ * only if we're filling in the ipsec_req_t.
+ */
+ if (ipsr == NULL)
+ /* make sure it's valid in context */
+ ret = parsealg(p, encr_algs);
+ else
+ /* also parse it into ipsr */
+ ret = (*cmd->c_func)(p, ipsr);
+
+ if (ret < 0) {
+ /* the parse command failed */
+ free(freeP);
+ return (0);
+ } else {
+ /* how far have we've come */
+ deltaP = p + strlen(p) + ioff;
+
+ /* parsed->next */
+ p = NULL;
+ break;
+ }
+ }
+ }
+
+ /* cmd->c_func = NULL, next alg */
+ p = NULL;
+ }
+
+ /* calculate how many bytes we've parsed */
+ bytes_parsed = deltaP - freeP;
+
+ /* finished with this */
+ free(freeP);
+
+ /* reset the per-policy parsing boolean */
+ encr_alg_set = FALSE;
+
+ /* as long as we got to a valid close bracket, we're fine */
+ if (!bclose_found)
+ return (0);
+
+ return (bytes_parsed);
+}
+
+/*
+ * Function:isIPsecPolicyValid
+ *
+ * Arguments: policy what the user is trying to set as policy properties.
+ *
+ * Description: This function validates an IPSec policy. The policy MUST be
+ * a single valid action, followed by a valid set of properties
+ * as specified by ipsec(7P). Note that we don't necessarily
+ * support all the actions that ipsec supports, see
+ * validIPsecActions[].
+ *
+ * Returns: _B_TRUE if the policy is valid, _B_FALSE if the policy is not.
+ *
+ * Note: this function only exists because ipSec has no API at this time.
+ */
+boolean_t
+isIPsecPolicyValid(char *policy, ipsec_req_t *ipsr)
+{
+ int c_len = 0;
+ char *cp;
+
+ if (policy == NULL)
+ return (_B_FALSE);
+
+ /* Parse the policy */
+ cp = policy;
+
+ /* actions first */
+ if ((c_len = isIPsecActionValid(cp)) == 0)
+ return (_B_FALSE);
+
+ cp += c_len;
+
+ while (isspace(*cp))
+ cp++;
+
+ /* now "{<properties>}" */
+ if ((c_len = parseIPsecProps(cp, ipsr)) == 0)
+ return (_B_FALSE);
+
+ cp += c_len;
+
+ /* trailing blanks are OK... */
+ while (isspace(*cp))
+ cp++;
+
+ /* ...but nothing else! */
+ return (*cp == '\0');
+}
diff --git a/deleted_files/usr/src/cmd/cmd-inet/common/conflib.h b/deleted_files/usr/src/cmd/cmd-inet/common/conflib.h
new file mode 100644
index 0000000000..a6ad92e964
--- /dev/null
+++ b/deleted_files/usr/src/cmd/cmd-inet/common/conflib.h
@@ -0,0 +1,122 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _CONFLIB_H
+#define _CONFLIB_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * conflib.h -- Prototypes and defines for conflib.c
+ * WARNING: This code assumes that an int is 32 bits.
+ */
+
+#include <netinet/in.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Static lengths of values. */
+#define MAX_LABEL_LEN 256
+#define MAX_SECTION_LEN 256
+#define MAX_VALUE_LEN 256
+#define MAX_FILENAME_LEN 256
+
+/* Error string readable by external programs */
+#define ERROR_SUBSTRING_LEN 256
+#define ERROR_STRING_LEN (MAX_FILENAME_LEN + ERROR_SUBSTRING_LEN)
+extern char ErrorString[];
+
+/*
+ * Check if OS has defined true or false. This code is portable between
+ * several OSs.
+ */
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+
+/* these are shared between mipagent and mipagentconfig */
+
+/* IPsec flags - what's in place to protect datagrams to/from an agent peer. */
+#define IPSEC_REQUEST_AH 0x01 /* regRequest using AH */
+#define IPSEC_REQUEST_ESP 0x02 /* regRequest using ESP */
+#define IPSEC_REPLY_AH 0x04 /* regReply using AH */
+#define IPSEC_REPLY_ESP 0x08 /* regReply using ESP */
+#define IPSEC_TUNNEL_AH 0x10 /* forward tunnel using AH */
+#define IPSEC_TUNNEL_ESP 0x20 /* forward tunnel using ESP */
+#define IPSEC_REVERSE_TUNNEL_AH 0x40 /* reverse tunnel using AH */
+#define IPSEC_REVERSE_TUNNEL_ESP 0x80 /* reverse tunnel using ESP */
+
+/* useful combinations */
+#define IPSEC_REQUEST_BOTH (IPSEC_REQUEST_AH | IPSEC_REQUEST_ESP)
+#define IPSEC_REPLY_BOTH (IPSEC_REPLY_AH | IPSEC_REPLY_ESP)
+#define IPSEC_TUNNEL_BOTH (IPSEC_TUNNEL_AH | IPSEC_TUNNEL_ESP)
+#define IPSEC_REVERSE_TUNNEL_BOTH \
+ (IPSEC_REVERSE_TUNNEL_AH | IPSEC_REVERSE_TUNNEL_ESP)
+
+/* useful for checking if there's a policy that should be invoked */
+#define IPSEC_REQUEST_ANY(x) ((x) & (IPSEC_REQUEST_BOTH))
+#define IPSEC_REPLY_ANY(x) ((x) & (IPSEC_REPLY_BOTH))
+#define IPSEC_TUNNEL_ANY(x) ((x) & (IPSEC_TUNNEL_BOTH))
+#define IPSEC_REVERSE_TUNNEL_ANY(x) ((x) & (IPSEC_REVERSE_TUNNEL_BOTH))
+
+/* useful for checking when user is requesting something that's not offered */
+#define IPSEC_ANY_AH(x) ((x) & (IPSEC_REQUEST_AH |\
+ IPSEC_REPLY_AH |\
+ IPSEC_TUNNEL_AH |\
+ IPSEC_REVERSE_TUNNEL_AH))
+
+#define IPSEC_ANY_ESP(x) ((x) & (IPSEC_REQUEST_ESP |\
+ IPSEC_REPLY_ESP |\
+ IPSEC_TUNNEL_ESP |\
+ IPSEC_REVERSE_TUNNEL_ESP))
+
+/* how policies are deliniated in CONF_FILE_NAME */
+#define IPSP_SEPARATOR ":"
+
+/* these functions are necessary to share IPsec functionality */
+int parseIPsecProps(char *, ipsec_req_t *);
+boolean_t isIPsecPolicyValid(char *, ipsec_req_t *);
+
+/* These functions mimic the Windows(tm) equivilants */
+int WritePrivateProfileString(char *, char *, char *, char *);
+int WritePrivateProfileInt(char *, char *, int, char *);
+int GetPrivateProfileString(char *, char *, char *, char *, int, char *);
+int GetPrivateProfileInt(char *, char *, int, char *);
+
+/* These functions were necessary for extra usability */
+char *IniListSections(char *, int *, int *);
+int DeletePrivateProfileLabel(char *, char *, char *);
+int DeletePrivateProfileSection(char *, char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CONFLIB_H */