/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 */ /* * ns_ldap.c * * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "automount.h" #include "../../../lib/libsldap/common/ns_sldap.h" /* * LDAP schema used for automounter: * * automountMapName: mapname i.e. auto_home, etc. * automountKey: contains the key i.e. the mount point * automountInformation: contains the mount options and remote mount location * description: an optional description (not used by automounter) * * For example, if auto_direct has the following line of data: * * /work -rw,intr,nosuid,noquota hosta:/export/work * * Then this would map to the the following LDAP entry: * * dn: automountKey=/work,automountMapName=auto_direct,... * automountKey: /work * automountInformation: -rw,intr,nosuid,noquota hosta:/export/work * objectclass: top * objectclass: automount * * In this container: * * dn: automountMapName=auto_direct,... * automountMapName: auto_direct * objectClass: top * objectClass: automountMap * * Note that the schema can be mapped and SSD's can be used to relocate * the default location of these entries. * */ #define CAPCHAR '%' #define MAXERROR 4000 static char *automountKey = NULL; static char *automountInformation = NULL; static char *defaultFilter = NULL; static int encode = 0; static int mastermap_callback_ldap(); static int directmap_callback(); static int ldap_err(int); static int ldap_match(); static int readdir_callback(); struct loadmaster_cbdata { char *ptr1; char **ptr2; char ***ptr3; }; struct loaddirect_cbdata { char *ptr1; char *ptr2; char **ptr3; char ***ptr4; }; struct dir_cbdata { struct dir_entry **list; struct dir_entry *last; int error; }; static char *tosunds_str(char *); static char *tounix_str(char *); static int isAttrMapped(char *orig, char *mapped) { char **s; char **mappedschema = NULL; mappedschema = __ns_ldap_getMappedAttributes("automount", orig); if (mappedschema == NULL) return (0); if (strcasecmp(mappedschema[0], mapped) != 0) { for (s = mappedschema; *s != NULL; s++) free(*s); free(mappedschema); return (0); } for (s = mappedschema; *s != NULL; s++) free(*s); free(mappedschema); return (1); } static int isObjectMapped(char *orig, char *mapped) { char **s; char **mappedschema = NULL; mappedschema = __ns_ldap_getMappedObjectClass("automount", orig); if (mappedschema == NULL) return (0); if (strcasecmp(mappedschema[0], mapped) != 0) { for (s = mappedschema; *s != NULL; s++) free(*s); free(mappedschema); return (0); } for (s = mappedschema; *s != NULL; s++) free(*s); free(mappedschema); return (1); } void init_ldap(char **stack, char ***stkptr) { /* * Check for version of the profile the client is using * * For version 1 profiles we do encoding of attributes * and use nisMap and nisObject schema for backward compatibility. * * For version 2 profiles we don't do encoding and use * automountMap and automount as default attributes (which can * then be overridden in libsldap if schema mapping is configured * in the profile). * * If profile version is not available, use version 2 as default * and syslog message. */ int rc, v2 = 1; void **paramVal = NULL; ns_ldap_error_t *errorp = NULL; struct __nsw_switchconfig *conf = NULL; struct __nsw_lookup *lkp = NULL; enum __nsw_parse_err pserr; int ldap_configured = 0; #ifdef lint stack = stack; stkptr = stkptr; #endif /* lint */ /* get nsswitch info of "automount */ conf = __nsw_getconfig("automount", &pserr); /* find out if LDAP backend is configured */ if (conf != NULL) { for (lkp = conf->lookups; lkp != NULL; lkp = lkp->next) { if (strcmp(lkp->service_name, "ldap") == 0) { ldap_configured = 1; break; } } /* free conf at the end of "if" bracket */ (void) __nsw_freeconfig(conf); } /* if ldap is not configured, init_ldap is a no op */ if (!ldap_configured) return; rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, ¶mVal, &errorp); if (rc != NS_LDAP_SUCCESS || !paramVal || !*paramVal) { syslog(LOG_ERR, "Can not determine version of LDAP profile" " that is used (%d, %s). Using version 2 profile" " defaults", rc, (errorp && errorp->message ? errorp->message : "")); (void) __ns_ldap_freeError(&errorp); } else { if (strcasecmp(*paramVal, NS_LDAP_VERSION_1) == 0) v2 = 0; (void) __ns_ldap_freeParam(¶mVal); } if (v2) { if (trace > 1) trace_prt(1, "init_ldap: setting up for version 2\n"); automountKey = "automountKey"; automountInformation = "automountInformation"; defaultFilter = "(&(objectClass=automount)(automountKey=%s))"; /* check for automountMapName mapped to nisMapName */ if (!isAttrMapped("automountMapName", "nisMapName")) return; /* check for automountKey mapped to cn */ if (!isAttrMapped("automountKey", "cn")) return; /* check for automountInformation mapped to nisMapEntry */ if (!isAttrMapped("automountInformation", "nisMapEntry")) return; /* check for automountMap mapped to nisMap */ if (!isObjectMapped("automountMap", "nisMap")) return; /* check for automount mapped to nisObject */ if (!isObjectMapped("automount", "nisObject")) return; if (trace > 1) trace_prt(1, "init_ldap: encode = TRUE\n"); encode = 1; } else { if (trace > 1) { trace_prt(1, "init_ldap: setting up for version 1\n"); trace_prt(1, "init_ldap: encode = TRUE\n"); } encode = 1; automountKey = "cn"; automountInformation = "nisMapEntry"; defaultFilter = "(&(objectClass=nisObject)(cn=%s))"; } } /*ARGSUSED*/ int getmapent_ldap(char *key, char *map, struct mapline *ml, char **stack, char ***stkptr, bool_t *iswildcard, bool_t isrestricted) { char *ldap_line = NULL; char *lp; int ldap_len, len; int nserr; if (trace > 1) trace_prt(1, "getmapent_ldap called\n"); if (trace > 1) { trace_prt(1, "getmapent_ldap: key=[ %s ]\n", key); } if (iswildcard) *iswildcard = FALSE; nserr = ldap_match(map, key, &ldap_line, &ldap_len); if (nserr) { if (nserr == __NSW_NOTFOUND) { /* Try the default entry "*" */ if ((nserr = ldap_match(map, "\\2a", &ldap_line, &ldap_len))) goto done; else { if (iswildcard) *iswildcard = TRUE; } } else goto done; } /* * at this point we are sure that ldap_match * succeeded so massage the entry by * 1. ignoring # and beyond * 2. trim the trailing whitespace */ if (lp = strchr(ldap_line, '#')) *lp = '\0'; len = strlen(ldap_line); if (len == 0) { nserr = __NSW_NOTFOUND; goto done; } lp = &ldap_line[len - 1]; while (lp > ldap_line && isspace(*lp)) *lp-- = '\0'; if (lp == ldap_line) { nserr = __NSW_NOTFOUND; goto done; } (void) strncpy(ml->linebuf, ldap_line, LINESZ); unquote(ml->linebuf, ml->lineqbuf); nserr = __NSW_SUCCESS; done: if (ldap_line) free((char *)ldap_line); if (trace > 1) trace_prt(1, "getmapent_ldap: exiting ...\n"); return (nserr); } static int ldap_match(char *map, char *key, char **ldap_line, int *ldap_len) { char searchfilter[LDAP_FILT_MAXSIZ]; int res, attr_found; ns_ldap_result_t *result = NULL; ns_ldap_error_t *errp = NULL; ns_ldap_entry_t *entry = NULL; char *ldapkey; int i; if (trace > 1) { trace_prt(1, "ldap_match called\n"); trace_prt(1, "ldap_match: key =[ %s ]\n", key); } /* * need to handle uppercase characters in the key because LDAP * searches are case insensitive. Note, key = attribute automountKey. */ if (encode) ldapkey = tosunds_str(key); else ldapkey = key; if (trace > 1) { trace_prt(1, "ldap_match: ldapkey =[ %s ]\n", ldapkey); } (void) sprintf(searchfilter, defaultFilter, ldapkey); if (trace > 1) trace_prt(1, " ldap_match: Requesting list for %s in %s\n", searchfilter, map); res = __ns_ldap_list(map, searchfilter, NULL, NULL, NULL, 0, &result, &errp, NULL, NULL); if (trace > 1) { if (res != NS_LDAP_SUCCESS) trace_prt(1, " ldap_match: __ns_ldap_list FAILED (%d)\n", res); else trace_prt(1, " ldap_match: __ns_ldap_list OK\n"); } if (res != NS_LDAP_SUCCESS && res != NS_LDAP_NOTFOUND) { if (errp) { if (verbose) { char errstr[MAXERROR]; (void) sprintf(errstr, gettext("ldap server can't list map," " '%s': '%s' - '%d'."), map, errp->message, errp->status); syslog(LOG_ERR, errstr); } __ns_ldap_freeError(&errp); } else { if (verbose) { char *errmsg; __ns_ldap_err2str(res, &errmsg); syslog(LOG_ERR, errmsg); } } if (result) __ns_ldap_freeResult(&result); return (ldap_err(res)); } if (res == NS_LDAP_NOTFOUND || result == NULL || result->entries_count == 0 || result->entry->attr_count == 0) { if (trace > 1) trace_prt(1, " ldap_match: no entries found\n"); if (errp) __ns_ldap_freeError(&errp); if (result) __ns_ldap_freeResult(&result); return (__NSW_NOTFOUND); } /* * get value of attribute nisMapEntry. This attribute contains a * list of mount options AND mount location for a particular mount * point (key). * For example: * * key: /work * ^^^^^ * (mount point) * * nisMapEntry: -rw,intr,nosuid,noquota hosta:/export/work * ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ * ( mount options ) (remote mount location) * */ attr_found = 0; entry = result->entry; for (i = 0; i < entry->attr_count; i++) { ns_ldap_attr_t *attr; attr = entry->attr_pair[i]; if (strcasecmp(attr->attrname, automountInformation) == 0) { char *attrval; attr_found = 1; if (encode) attrval = tounix_str(attr->attrvalue[0]); else attrval = attr->attrvalue[0]; *ldap_len = strlen(key) + strlen(attrval); /* * so check for the length; it should be less than * LINESZ */ if ((*ldap_len + 2) > LINESZ) { syslog(LOG_ERR, "ldap server map %s, entry for %s" " is too long %d chars (max %d)", map, key, (*ldap_len + 2), LINESZ); __ns_ldap_freeResult(&result); return (__NSW_UNAVAIL); } *ldap_line = (char *)malloc(*ldap_len + 2); if (*ldap_line == NULL) { syslog(LOG_ERR, "ldap_match: malloc failed"); __ns_ldap_freeResult(&result); return (__NSW_UNAVAIL); } (void) sprintf(*ldap_line, "%s", attrval); break; } } __ns_ldap_freeError(&errp); __ns_ldap_freeResult(&result); if (!attr_found) return (__NSW_NOTFOUND); if (trace > 1) trace_prt(1, " ldap_match: found: %s\n", *ldap_line); return (__NSW_SUCCESS); } int loadmaster_ldap(char *mapname, char *defopts, char **stack, char ***stkptr) { char searchfilter[LDAP_FILT_MAXSIZ]; int res; ns_ldap_result_t *result = NULL; ns_ldap_error_t *errp = NULL; struct loadmaster_cbdata master_cbdata; if (trace > 1) trace_prt(1, "loadmaster_ldap called\n"); master_cbdata.ptr1 = defopts; master_cbdata.ptr2 = stack; master_cbdata.ptr3 = stkptr; /* filter gets all the entries for the specified mapname */ (void) sprintf(searchfilter, defaultFilter, "*"); if (trace > 1) trace_prt(1, "loadmaster_ldap: Requesting list for %s in %s\n", searchfilter, mapname); res = __ns_ldap_list(mapname, searchfilter, NULL, NULL, NULL, 0, &result, &errp, mastermap_callback_ldap, (void *) &master_cbdata); if (trace > 1) trace_prt(1, "loadmaster_ldap: __ns_ldap_list just returned: %d\n", res); if (res != NS_LDAP_SUCCESS) { if (errp) { char errstr[MAXERROR]; if (verbose) { (void) sprintf(errstr, gettext( "ldap server can't list map," "'%s': '%s' - '%d'."), mapname, errp->message, errp->status); syslog(LOG_ERR, errstr); } __ns_ldap_freeError(&errp); } else { if (verbose) { char *errmsg; __ns_ldap_err2str(res, &errmsg); syslog(LOG_ERR, errmsg); } } if (result) __ns_ldap_freeResult(&result); return (ldap_err(res)); } if (trace > 1) trace_prt(1, "loadmaster_ldap: calling __ns_ldap_freeResult...\n"); __ns_ldap_freeResult(&result); if (trace > 1) trace_prt(1, "loadmaster_ldap: about to return __NSW_SUCCESS...\n"); return (__NSW_SUCCESS); } int loaddirect_ldap(char *nsmap, char *localmap, char *opts, char **stack, char ***stkptr) { char searchfilter[LDAP_FILT_MAXSIZ]; int res; ns_ldap_result_t *result = NULL; ns_ldap_error_t *errp = NULL; struct loaddirect_cbdata direct_cbdata; if (trace > 1) { trace_prt(1, "loaddirect_ldap called\n"); } direct_cbdata.ptr1 = opts; direct_cbdata.ptr2 = localmap; direct_cbdata.ptr3 = stack; direct_cbdata.ptr4 = stkptr; /* filter gets all the entries for the specified mapname */ (void) sprintf(searchfilter, defaultFilter, "*"); if (trace > 1) trace_prt(1, "loaddirect_ldap: Requesting list for %s in %s\n", searchfilter, nsmap); res = __ns_ldap_list(nsmap, searchfilter, NULL, NULL, NULL, 0, &result, &errp, directmap_callback, (void *) &direct_cbdata); if (res != NS_LDAP_SUCCESS) { if (errp) { char errstr[MAXERROR]; if (verbose) { (void) sprintf(errstr, gettext("ldap server can't list map," " '%s': '%s' - '%d'."), nsmap, errp->message, errp->status); syslog(LOG_ERR, errstr); } __ns_ldap_freeError(&errp); } else { if (verbose) { char *errmsg; __ns_ldap_err2str(res, &errmsg); syslog(LOG_ERR, errmsg); } } if (result) __ns_ldap_freeResult(&result); return (ldap_err(res)); } __ns_ldap_freeResult(&result); return (__NSW_SUCCESS); } static int ldap_err(int err) { if (trace > 1) trace_prt(1, "ldap_err called\n"); switch (err) { case NS_LDAP_SUCCESS: return (__NSW_SUCCESS); case NS_LDAP_NOTFOUND: return (__NSW_NOTFOUND); case NS_LDAP_PARTIAL: return (__NSW_TRYAGAIN); default: return (__NSW_UNAVAIL); } } static int mastermap_callback_ldap(ns_ldap_entry_t *entry, void *udata) { char *key, *contents, *pmap, *opts; char dir[LINESZ], map[LINESZ], qbuff[LINESZ]; char cont_temp[LINESZ], key_temp[LINESZ]; int key_len, contents_len; struct loadmaster_cbdata *temp = (struct loadmaster_cbdata *)udata; char *defopts = temp->ptr1; char **stack = temp->ptr2; char ***stkptr = temp->ptr3; int i; if (trace > 1) { trace_prt(1, "mastermap_callback_ldap called\n"); trace_prt(1, "mastermap_callback_ldap: entry=%x\n", entry); if (entry) { trace_prt(1, "mastermap_callback_ldap: entry->attr_count=[ %d ]\n", entry->attr_count); } } /* * For the current entry, obtain the values of the cn and the * nisMapEntry attributes and the length of each value (cn=key, * nisMapEntry=contents). * We skip the description. Even though LDAP allows for multiple * values per attribute, we take only the 1st value for each * attribute because the automount data is organized as such. */ key_len = 0; contents_len = 0; key = NULL; contents = NULL; for (i = 0; i < entry->attr_count; i++) { ns_ldap_attr_t *attr; attr = entry->attr_pair[i]; if (trace > 1) { trace_prt(1, "mastermap_callback_ldap: attr[%d]: %s=%s\n", i, attr->attrname, attr->attrvalue[0]); } if (strcasecmp(attr->attrname, automountInformation) == 0) { if (encode) (void) strncpy(cont_temp, tounix_str(attr->attrvalue[0]), LINESZ); else (void) strncpy(cont_temp, attr->attrvalue[0], LINESZ); contents = cont_temp; contents_len = strlen(contents); if (trace > 1) { trace_prt(1, "mastermap_callback_ldap: contents=[ %s ]," " contents_len=[ %d ]\n", contents, contents_len); } } if (strcasecmp(attr->attrname, automountKey) == 0) { if (encode) (void) strncpy(key_temp, tounix_str(attr->attrvalue[0]), LINESZ); else (void) strncpy(key_temp, attr->attrvalue[0], LINESZ); key = key_temp; key_len = strlen(key); if (trace > 1) { trace_prt(1, "mastermap_callback_ldap: key=[ %s ]," " key_len=[ %d ]\n", key, key_len); } } } if (key_len >= LINESZ || contents_len >= LINESZ) return (0); if (key_len < 2 || contents_len < 2) return (0); while (isspace(*contents)) contents++; if (contents == NULL) return (0); if (isspace(*key) || *key == '#') return (0); (void) strncpy(dir, key, key_len); dir[key_len] = '\0'; if (trace > 1) trace_prt(1, "mastermap_callback_ldap: dir= [ %s ]\n", dir); for (i = 0; i < LINESZ; i++) qbuff[i] = ' '; if (macro_expand("", dir, qbuff, sizeof (dir))) { syslog(LOG_ERR, "%s in ldap server map: entry too long (max %d chars)", dir, sizeof (dir) - 1); return (0); } (void) strncpy(map, contents, contents_len); map[contents_len] = '\0'; if (trace > 1) trace_prt(1, "mastermap_callback_ldap: map= [ %s ]\n", map); if (macro_expand("", map, qbuff, sizeof (map))) { syslog(LOG_ERR, "%s in ldap server map: entry too long (max %d chars)", map, sizeof (map) - 1); return (0); } pmap = map; while (*pmap && isspace(*pmap)) pmap++; /* skip blanks in front of map */ opts = pmap; while (*opts && !isspace(*opts)) opts++; if (*opts) { *opts++ = '\0'; while (*opts && isspace(*opts)) opts++; if (*opts == '-') opts++; else opts = defopts; } /* * Check for no embedded blanks. */ if (strcspn(opts, " ") == strlen(opts)) { if (trace > 1) trace_prt(1, "mastermap_callback_ldap: dir=[ %s ], pmap=[ %s ]\n", dir, pmap); dirinit(dir, pmap, opts, 0, stack, stkptr); } else { char *dn = NULL; /* get the value for the dn */ for (i = 0; i < entry->attr_count; i++) { ns_ldap_attr_t *attr; attr = entry->attr_pair[i]; if (strcasecmp(attr->attrname, "dn") == 0) { dn = attr->attrvalue[0]; break; } } pr_msg( "Warning: invalid entry for %s in ldap server" " dn: %s ignored.\n", dir, dn); } if (trace > 1) trace_prt(1, "mastermap_callback_ldap exiting...\n"); return (0); } static int directmap_callback(ns_ldap_entry_t *entry, void *udata) { char *key; char dir[256]; int key_len; struct loaddirect_cbdata *temp = (struct loaddirect_cbdata *)udata; char *opts = temp->ptr1; char *localmap = temp->ptr2; char **stack = temp->ptr3; char ***stkptr = temp->ptr4; int i; /* * For the current entry, obtain the value and length of the cn i.e. * the contents of key and its key length. */ key_len = 0; key = NULL; for (i = 0; i < entry->attr_count; i++) { ns_ldap_attr_t *attr; attr = entry->attr_pair[i]; if (strcasecmp(attr->attrname, automountKey) == 0) { if (encode) key = tounix_str(attr->attrvalue[0]); else key = attr->attrvalue[0]; key_len = strlen(key); break; } } if (key_len >= 100 || key_len < 2) return (0); if (isspace(*key) || *key == '#') return (0); (void) strncpy(dir, key, key_len); dir[key_len] = '\0'; dirinit(dir, localmap, opts, 1, stack, stkptr); return (0); } int getmapkeys_ldap(char *nsmap, struct dir_entry **list, int *error, int *cache_time, char **stack, char ***stkptr) { char searchfilter[LDAP_FILT_MAXSIZ]; int res; ns_ldap_result_t *result = NULL; ns_ldap_error_t *errp = NULL; struct dir_cbdata readdir_cbdata; #ifdef lint stack = stack; stkptr = stkptr; #endif /* lint */ if (trace > 1) trace_prt(1, "getmapkeys_ldap called\n"); *cache_time = RDDIR_CACHE_TIME; *error = 0; readdir_cbdata.list = list; readdir_cbdata.last = NULL; /* filter gets all the entries for the specified mapname */ (void) sprintf(searchfilter, defaultFilter, "*"); if (trace > 1) trace_prt(1, "getmapkeys_ldap: Requesting list for %s in %s\n", searchfilter, nsmap); res = __ns_ldap_list(nsmap, searchfilter, NULL, NULL, NULL, 0, &result, &errp, readdir_callback, (void *) &readdir_cbdata); if (trace > 1) trace_prt(1, " getmapkeys_ldap: __ns_ldap_list returned %d\n", res); if (readdir_cbdata.error) *error = readdir_cbdata.error; if (res != NS_LDAP_SUCCESS && res != NS_LDAP_NOTFOUND) { if (errp) { if (verbose) { char errstr[MAXERROR]; (void) sprintf(errstr, gettext( "ldap server can't list map," " '%s': '%s' - '%d'."), nsmap, errp->message, errp->status); syslog(LOG_ERR, errstr); } __ns_ldap_freeError(&errp); } else { if (verbose) { char *errmsg; __ns_ldap_err2str(res, &errmsg); syslog(LOG_ERR, errmsg); } } if (result) __ns_ldap_freeResult(&result); if (*error == 0) *error = ECOMM; return (ldap_err(res)); } if (result) __ns_ldap_freeResult(&result); return (__NSW_SUCCESS); } static int readdir_callback(const ns_ldap_entry_t *entry, const void *udata) { char *key; int key_len; struct dir_cbdata *temp = (struct dir_cbdata *)udata; struct dir_entry **list = temp->list; struct dir_entry *last = temp->last; int i; if (trace > 1) trace_prt(1, "readdir_callback called\n"); /* * For the current entry, obtain the value and length of the cn i.e. the * contents of key and its key length. */ key_len = 0; key = NULL; if (trace > 1) trace_prt(1, "readdir_callback: entry->attr_count=[ %d ]\n", entry->attr_count); for (i = 0; i < entry->attr_count; i++) { ns_ldap_attr_t *attr; attr = entry->attr_pair[i]; if (trace > 1) trace_prt(1, "readdir_callback: attr->attrname=[ %s ]\n", attr->attrname); if (strcasecmp(attr->attrname, automountKey) == 0) { if (encode) key = tounix_str(attr->attrvalue[0]); else key = attr->attrvalue[0]; key_len = strlen(key); if (trace > 1) trace_prt(1, "readdir_callback: key=[ %s ], key_len=[ %d ]\n", key, key_len); break; } } if (key_len >= 100 || key_len < 2) return (0); if (isspace(*key) || *key == '#') return (0); /* * Wildcard entry should be ignored - following entries should continue * to be read to corroborate with the way we search for entries in * LDAP, i.e., first for an exact key match and then a wildcard * if there's no exact key match. */ if (key[0] == '*' && key[1] == '\0') return (0); if (add_dir_entry(key, list, &last)) { temp->error = ENOMEM; return (1); } temp->last = last; temp->error = 0; if (trace > 1) trace_prt(1, "readdir_callback returning 0...\n"); return (0); } /* * Puts CAPCHAR in front of uppercase characters or surrounds a set of * contiguous uppercase characters with CAPCHARS and square brackets. * * For example (assuming CAPCHAR = '%'): * * if str = Abc, it returns %Abc * if str = ABc, it returns %[AB]c * if str = AbC, it returns %Ab%C * */ static char * tosunds_str(char *str) { static char buf[BUFSIZ]; int i, j, er = FALSE; #ifdef NEWCAP int openBracket = FALSE, closeBracket = FALSE; #endif (void) memset(buf, 0, BUFSIZ); j = 0; for (i = 0; i < strlen(str); i++) { /* Check the current element */ if (isupper(str[i])) { #ifdef NEWCAP /* check the next element */ if (isupper(str[i+1])) { if (openBracket == FALSE) { openBracket = TRUE; buf[j] = CAPCHAR; buf[j+1] = '['; j += 2; } } else { if (openBracket == FALSE) { buf[j] = CAPCHAR; j++; } else { openBracket = FALSE; closeBracket = TRUE; } } #else buf[j++] = CAPCHAR; #endif } buf[j] = str[i]; j++; #ifdef NEWCAP if (closeBracket == TRUE) { closeBracket = FALSE; buf[j] = ']'; j++; } #endif if (j >= BUFSIZ) { er = TRUE; break; } } if (er) { syslog(LOG_ERR, "Buffer size exceeded."); (void) memset(buf, 0, BUFSIZ); } else buf[j] = '\0'; return (buf); } /* * Reverses what tosunds_str() did */ static char * tounix_str(char *str) { static char buf[BUFSIZ]; int i, j; int openBracket = FALSE; (void) memset(buf, 0, BUFSIZ); j = 0; for (i = 0; i < strlen(str); i++) { if (str[i] == '%') { if (isupper(str[i+1])) { i += 1; } else if ((str[i+1] == '[') && (isupper(str[i+2]))) { i += 2; openBracket = TRUE; } } else if (str[i] == ']') { if ((isupper(str[i-1])) && (openBracket == TRUE)) i += 1; openBracket = FALSE; } buf[j] = str[i]; j++; } return (buf); }