/* This module is derived from the original libiiimp. And the file name is role-data-client.c. In order to inspect client environment, currently use this file also in libiiimcf. But it will be at least partly rewritten mainly for procuring portability. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(OS_ARCH) && defined(HAVE_SYSINFO) && defined(HAVE_SYS_SYSTEMINFO_H) #include #endif #include "iiimcfint.h" #define NODE_KEY "node=" #define NODE_KEY_LEN (5) #define SERVICE_KEY "service=" #define SERVICE_KEY_LEN (8) #define CERT_FILE "tls_cert=" #define CERT_FILE_LEN (9) #define CERT_KEY_FILE "tls_key=" #define CERT_KEY_FILE_LEN (8) #define CERT_CA_FILE "tls_cafile=" #define CERT_CA_FILE_LEN (11) #define CERT_CA_PATH "tls_capath=" #define CERT_CA_PATH_LEN (11) #define USE_TLS "use_tls=" #define USE_TLS_LEN (8) #define SERVER_FILE ".iiim/server" #define SERVER_FILE_LEN (12) #define SERVER_COMPAT_FILE ".iiimp" #define SERVER_COMPAT_FILE_LEN (6) #define SERVER_COMPAT_KEY "iiimp.server=iiimp://" #define SERVER_COMPAT_KEY_LEN (21) #define CONFIG_DIR_BASE ".iiim" #define CONFIG_DIR_AUTH ".iiim/auth" #define CONFIG_FILE_PASSWD ".iiim/auth/passwd" #define PASSWORD_FILE_LEN (17) #define AUTH_PASSWORD_LEN (32) #define HOME_ENV "HOME" #define IIIM_SERVER_ENV "IIIM_SERVER" #define CLIENT_TYPE "generic IIIMP client" #define POSITION_HEAD(p, n) \ for (; 0 < n; --(n), (p)++) { \ if ((' ' != *(p)) && ('\t' != *(p)) && \ ('\r' != *(p)) && ('\n' != *(p))) { \ break; \ } \ } \ if ((0 < (n)) && ((',' == *(p)) || (';' == *(p)))) { \ --(n); \ (p)++; \ } \ for (; 0 < n; --(n), (p)++) { \ if ((' ' != *(p)) && ('\t' != *(p)) && \ ('\r' != *(p)) && ('\n' != *(p))) { \ break; \ } \ } #define POSITION_TAIL(p, n) \ for (; 0 < n; --(n), (p)++) { \ if ((',' == *(p)) || (';' == *(p)) || \ (' ' == *(p)) || ('\t' == *(p)) || \ ('\r' == *(p)) || ('\n' == *(p))) { \ break; \ } \ } #define POSITION_TAIL_COMPAT(p, n) \ for (; 0 < n; --(n), (p)++) { \ if ((':' == *(p)) || ('\r' == *(p)) || ('\n' == *(p))) { \ break; \ } \ } static IIIMF_status get_param( const char ** buf, size_t * nbyte, const char * key, size_t key_len, char ** param_ret ) { const char * b; const char * p; size_t n; size_t m; size_t len; char * param; b = *buf; n = *nbyte; if (n < key_len) return IIIMF_STATUS_CONFIG; if (0 != strncasecmp(b, key, key_len)) { return IIIMF_STATUS_CONFIG; } b += key_len; n -= key_len; p = b; m = n; POSITION_TAIL(b, n); len = (m - n); param = (char *)malloc(len + 1); if (NULL == param) return IIIMF_STATUS_MALLOC; (void)memcpy(param, p, len); *(param + len) = '\0'; *buf = b; *nbyte = n; *param_ret = param; return IIIMF_STATUS_SUCCESS; } static IIIMF_status get_param_compat( const char ** buf, size_t * nbyte, const char * key, size_t key_len, char ** param_ret ) { const char * b; const char * p; size_t n; size_t m; size_t len; char * param; b = *buf; n = *nbyte; if (n < key_len) return IIIMF_STATUS_CONFIG; if (0 != strncasecmp(b, key, key_len)) { return IIIMF_STATUS_CONFIG; } b += key_len; n -= key_len; p = b; m = n; POSITION_TAIL_COMPAT(b, n); len = (m - n); param = (char *)malloc(len + 1); if (NULL == param) return IIIMF_STATUS_MALLOC; (void)memcpy(param, p, len); *(param + len) = '\0'; *buf = b; *nbyte = n; *param_ret = param; return IIIMF_STATUS_SUCCESS; } static void iiimcf_client_config_free( IIIMCF_client_conf *pconf ) { IIIMCF_client_conf *pc; IIIMCF_client_conf *pc2; if (!pconf) return; for (pc = pconf; pc; ) { pc2 = pc->next; if(pc->server_node) free(pc->server_node); if(pc->service) free(pc->service); if(pc->cert_file) free(pc->cert_file); if(pc->cert_key) free(pc->cert_key); if(pc->ca_file) free(pc->ca_file); if(pc->ca_path) free(pc->ca_path); free(pc); pc = pc2; } } static IIIMCF_client_conf * iiimcf_client_config_new( char *node, char *service ) { IIIMCF_client_conf *ret; ret = malloc(sizeof(*ret)); if (!ret) return NULL; memset(ret, 0, sizeof(*ret)); ret->server_node = node; ret->service = service; return ret; } static IIIMF_status iiimcf_client_file_server( IIIMCF_client_env *penv ) { int fd; IIIMF_status status; char * server_file; size_t server_file_len; size_t home_dir_len; struct stat st; int stat_ret; char * pa; const char * p; size_t rest; IIIMCF_client_conf *pconf = NULL; char * node = NULL; if (!penv->home_dir) return IIIMF_STATUS_CONFIG; home_dir_len = strlen(penv->home_dir); server_file_len = (home_dir_len + 1 + SERVER_FILE_LEN); server_file = (char *)malloc(server_file_len + 1); if (NULL == server_file) { return IIIMF_STATUS_MALLOC; } (void)strcpy(server_file, penv->home_dir); *(server_file + home_dir_len) = '/'; (void)strcpy(server_file + home_dir_len + 1, SERVER_FILE); fd = open(server_file, O_RDONLY, 0); free(server_file); if (fd < 0) return IIIMF_STATUS_CONFIG; stat_ret = fstat(fd, &st); if (stat_ret < 0) { return IIIMF_STATUS_CONFIG; } pa = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); (void)close(fd); if (NULL == pa) return IIIMF_STATUS_CONFIG; p = pa; rest = st.st_size; /* create client pconfig */ for (; rest > 0; ) { POSITION_HEAD(p, rest); if (rest == 0) break; if (!strncasecmp(p, NODE_KEY, NODE_KEY_LEN)) { IIIMCF_client_conf *pconf_next; status = get_param(&p, &rest, NODE_KEY, NODE_KEY_LEN, &node); if (IIIMF_STATUS_SUCCESS != status) { goto error; } if (!penv->pconf) { /* if penv->pconf is not yet initialized, the first one */ penv->pconf = iiimcf_client_config_new(node, NULL); if (!penv->pconf) { free(node); goto error; } pconf = penv->pconf; } else { /* otherwise, create new pconfig and link to penv->pconf */ pconf_next = iiimcf_client_config_new(node, NULL); if (!pconf_next) { free(node); goto error; } pconf->next = pconf_next; pconf = pconf_next; } } else if (!strncasecmp(p, SERVICE_KEY, SERVICE_KEY_LEN)) { if (!pconf) goto error; status = get_param(&p, &rest, SERVICE_KEY, SERVICE_KEY_LEN, &pconf->service); if (IIIMF_STATUS_SUCCESS != status) { goto error; } } else if (!strncasecmp(p, CERT_FILE, CERT_FILE_LEN)) { if (!pconf) goto error; status = get_param(&p, &rest, CERT_FILE, CERT_FILE_LEN, &pconf->cert_file); if (IIIMF_STATUS_SUCCESS != status) { goto error; } } else if (!strncasecmp(p, CERT_KEY_FILE, CERT_KEY_FILE_LEN)) { if (!pconf) goto error; status = get_param(&p, &rest, CERT_FILE, CERT_FILE_LEN, &pconf->cert_key); if (IIIMF_STATUS_SUCCESS != status) { goto error; } } else if (!strncasecmp(p, CERT_CA_FILE, CERT_CA_FILE_LEN)) { if (!pconf) goto error; status = get_param(&p, &rest, CERT_CA_FILE, CERT_CA_FILE_LEN, &pconf->ca_file); if (IIIMF_STATUS_SUCCESS != status) { goto error; } } else if (!strncasecmp(p, CERT_CA_PATH, CERT_CA_PATH_LEN)) { if (!pconf) goto error; status = get_param(&p, &rest, CERT_CA_PATH, CERT_CA_PATH_LEN, &pconf->ca_path); if (IIIMF_STATUS_SUCCESS != status) { goto error; } } else if (!strncasecmp(p, USE_TLS, USE_TLS_LEN)) { char *use_tls; if (!pconf) goto error; status = get_param(&p, &rest, USE_TLS, USE_TLS_LEN, &use_tls); if (IIIMF_STATUS_SUCCESS != status) { goto error; } if (!strcasecmp(use_tls, "yes")) { pconf->use_tls = 1; } free(use_tls); } else { POSITION_TAIL(p, rest); } } (void)munmap(pa, st.st_size); return IIIMF_STATUS_SUCCESS; error: iiimcf_client_config_free(penv->pconf); penv->pconf = NULL; (void)munmap(pa, st.st_size); return IIIMF_STATUS_CONFIG; } static IIIMF_status iiimcf_client_file_compat_server( IIIMCF_client_env *penv ) { int fd; IIIMF_status status; char * server_file; size_t server_file_len; size_t home_dir_len; struct stat st; int stat_ret; char * pa; const char * p; size_t rest; char * node = NULL; char * service; if (!penv->home_dir) return IIIMF_STATUS_CONFIG; home_dir_len = strlen(penv->home_dir); server_file_len = (home_dir_len + 1 + SERVER_COMPAT_FILE_LEN); server_file = (char *)malloc(server_file_len + 1); if (NULL == server_file) { return IIIMF_STATUS_MALLOC; } (void)strcpy(server_file, penv->home_dir); *(server_file + home_dir_len) = '/'; (void)strcpy(server_file + home_dir_len + 1, SERVER_COMPAT_FILE); fd = open(server_file, O_RDONLY, 0); free(server_file); if (fd < 0) return IIIMF_STATUS_CONFIG; stat_ret = fstat(fd, &st); if (stat_ret < 0) { return IIIMF_STATUS_CONFIG; } pa = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); (void)close(fd); if (NULL == pa) return IIIMF_STATUS_CONFIG; p = pa; rest = st.st_size; while (0 < rest) { for (; 0 < rest; --rest, p++) { if (('\r' == *p) || ('\n' == *p)) { p += 1; rest -= 1; break; } } if (rest < SERVER_COMPAT_KEY_LEN) break; status = get_param_compat(&p, &rest, SERVER_COMPAT_KEY, SERVER_COMPAT_KEY_LEN, &node); if (IIIMF_STATUS_SUCCESS == status) { p += 1; rest -= 1; break; } } if (!node) { return IIIMF_STATUS_CONFIG; } status = get_param_compat(&p, &rest, "", 0, &service); (void)munmap(pa, st.st_size); if ('\0' == *service) { free(service); service = NULL; } if (IIIMF_STATUS_SUCCESS == status) { penv->pconf = iiimcf_client_config_new(node, service); } return status; } static IIIMF_status iiimcf_client_environ_server( IIIMCF_client_env *penv ) { IIIMF_status status; const char * p; size_t rest; char * node; char * service; p = getenv(IIIM_SERVER_ENV); if (NULL == p) return IIIMF_STATUS_FAIL; rest = strlen(p); status = get_param(&p, &rest, "", 0, &node); if (IIIMF_STATUS_SUCCESS != status) { return status; } POSITION_HEAD(p, rest); status = get_param(&p, &rest, "", 0, &service); penv->pconf = iiimcf_client_config_new(node, service); return IIIMF_STATUS_SUCCESS; } static void auth_password_generate( char * password, size_t length ) { int fd; unsigned int seed; int c; int i; int r; unsigned int * p; size_t n; char * c62; *(password + length) = '\0'; c62 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; fd = open("/dev/random", O_RDONLY, 0); if (0 <= fd) { r = 0; n = ((sizeof (unsigned int)) * length); p = (unsigned int * )malloc(n); if (NULL != p) { r = read(fd, p, n); } (void)close(fd); if (r == length) { for (i = 0; i < length; i++) { *(password + i) = *(c62 + (*(p + i) % 62)); } free(p); return; } free(p); } seed = (time(NULL) + getpid()); srand(seed); for (i = 0; i < length; i++) { c = rand(); *(password + i) = *(c62 + (c % 62)); } return; } static int auth_password_file_init( char * password_file, size_t home_dir_len ) { int fd; char pwd_buf[AUTH_PASSWORD_LEN + 1]; struct stat st; ssize_t len; /* ${HOME}/.iiim */ (void)strcpy(password_file + home_dir_len, CONFIG_DIR_BASE); if (0 != stat(password_file, &st)) { if (ENOENT != errno) return -1; if (0 != mkdir(password_file, 0777)) return -1; } /* ${HOME}/.iiim/auth */ (void)strcpy(password_file + home_dir_len, CONFIG_DIR_AUTH); if (0 != stat(password_file, &st)) { if (ENOENT != errno) return -1; if (0 != mkdir(password_file, 0700)) return -1; } /* ${HOME}/.iiim/auth/password */ (void)strcpy(password_file + home_dir_len, CONFIG_FILE_PASSWD); fd = open(password_file, O_CREAT | O_WRONLY, 0600); if (-1 == fd) return -1; auth_password_generate(pwd_buf, AUTH_PASSWORD_LEN); len = write(fd, pwd_buf, AUTH_PASSWORD_LEN + 1); (void)close(fd); if ((AUTH_PASSWORD_LEN + 1) == len) { return 0; } else { return -1; } } static int auth_password_file_open( const char * home_dir ) { char * password_file; char * home_env; int home_dir_len; int len; struct stat st; int fd; password_file = NULL; if (NULL == home_dir) { home_env = getenv("HOME"); if (NULL != home_env) { home_dir = home_env; } if (NULL == home_dir) { return -1; } } home_dir_len = strlen(home_dir); len = (home_dir_len + 1 + PASSWORD_FILE_LEN); password_file = malloc(len + 1); if (NULL == password_file) { return -1; } (void)strcpy(password_file, home_dir); *(password_file + home_dir_len) = '/'; home_dir_len += 1; (void)strcpy(password_file + home_dir_len, CONFIG_FILE_PASSWD); if (0 != stat(password_file, &st)) { (void)auth_password_file_init(password_file, home_dir_len); } fd = open(password_file, O_RDONLY, 0); free(password_file); return fd; } static IIIMF_status iiimcf_client_auth_password( IIIMCF_client_env *penv ) { char * password; if (penv->password) return IIIMF_STATUS_SUCCESS; password = strdup(""); #if 0 int fd; int len; int i; char pwd_buf[AUTH_PASSWORD_LEN + 1]; password = NULL; fd = -1; if (!penv->home_dir) return IIIMF_STATUS_CONFIG; fd = auth_password_file_open(penv->home_dir); if (-1 == fd) return IIIMF_STATUS_CONFIG; len = read(fd, pwd_buf, AUTH_PASSWORD_LEN); (void)close(fd); if (AUTH_PASSWORD_LEN != len) return IIIMF_STATUS_CONFIG; for (i = 0; i < AUTH_PASSWORD_LEN; i++) { if (0 == isalnum(pwd_buf[i])) { return IIIMF_STATUS_CONFIG; } } if (AUTH_PASSWORD_LEN != i) { return IIIMF_STATUS_CONFIG; } password = malloc(AUTH_PASSWORD_LEN + 1); if (NULL == password) return IIIMF_STATUS_MALLOC; (void)memcpy(password, pwd_buf, AUTH_PASSWORD_LEN); *(password + AUTH_PASSWORD_LEN) = '\0'; penv->password = password; #endif return IIIMF_STATUS_SUCCESS; } static IIIMF_status iiimcf_client_os_arch( IIIMCF_client_env *penv ) { #if defined(OS_ARCH) penv->os_arch = strdup(OS_ARCH); #else /* !OS_ARCH */ #if defined(HAVE_SYSINFO) && defined(SI_ARCHITECTURE) { char arch[16]; int ret; ret = sysinfo(SI_ARCHITECTURE, arch, sizeof (arch)); if (-1 == ret) { penv->os_arch = NULL; } else if ((0 == strcmp(arch, "sparc")) || (0 == strcmp(arch, "ppc"))) { penv->os_arch = strdup(arch); } else if (0 == strcmp(arch, "i386")) { penv->os_arch = strdup("x86"); } else { penv->os_arch = strdup("Unknown"); } } #else /* !HAVE_SYSINFO || !SI_ARCHITECTURE */ penv->os_arch = strdup("Unknown"); #endif /* !HAVE_SYSINFO || !SI_ARCHITECTURE */ #endif /* !OS_ARCH */ if (!penv->os_arch) return IIIMF_STATUS_MALLOC; return IIIMF_STATUS_SUCCESS; } static IIIMF_status dir_valid(const char * path_name, uid_t euid) { struct stat st; #if !defined(S_IAMB) #define S_IAMB 0x1FF #endif /* !S_IAMB */ if ((0 == lstat(path_name, &st)) && (0 != S_ISDIR(st.st_mode)) && (euid == st.st_uid) && ((S_IAMB & st.st_mode) == S_IRWXU)) { return IIIMF_STATUS_SUCCESS; } else { return IIIMF_STATUS_FAIL; } } static IIIMF_status iiimcf_alternate_unix_domain_socket_file_dir( IIIMCF_client_env * penv, char ** path_name ) { DIR * dir; struct dirent * dirent; char * base_name; size_t base_name_len; char * dir_name; size_t dir_name_len; IIIMF_status found; uid_t euid; dir = opendir("/tmp"); if (NULL == dir) return IIIMF_STATUS_FAIL; base_name_len = (strlen(".iiimp-unix-") + strlen(penv->user_name) + 1); base_name = (char *)malloc(base_name_len + 1); if (NULL == base_name) { closedir(dir); return IIIMF_STATUS_MALLOC; } snprintf(base_name, base_name_len + 1, ".iiimp-unix-%s-", penv->user_name); euid = geteuid(); found = IIIMF_STATUS_FAIL; while (NULL != (dirent = readdir(dir))) { if (0 != strncmp(dirent->d_name, base_name, base_name_len)) { continue; } dir_name_len = (strlen("/tmp") + 1 + strlen(dirent->d_name) + 1); dir_name = (char *)malloc(dir_name_len); if (NULL == dir_name) { found = IIIMF_STATUS_MALLOC; break; } snprintf(dir_name, dir_name_len, "/tmp/%s", dirent->d_name); found = dir_valid(dir_name, euid); if (IIIMF_STATUS_SUCCESS == found) { (*path_name) = dir_name; break; } free(dir_name); } free(base_name); closedir(dir); return found; } IIIMF_status iiimcf_create_client_env( IIIMCF_attr attr, IIIMCF_client_env **ppenv ) { IIIMCF_client_env *penv; IIIMCF_client_conf *pconf; IIIMF_status st; const char *server_node, *service, *user_name, *password; const char *clientname, *x_display_name, *x_server_vendor; server_node = service = user_name = password = NULL; clientname = x_display_name = x_server_vendor = NULL; penv = (IIIMCF_client_env *)malloc(sizeof (IIIMCF_client_env)); if (!penv) return IIIMF_STATUS_MALLOC; memset(penv, 0, sizeof(*penv)); st = iiimcf_attr_get_string_value(attr, IIIMCF_ATTR_SERVER_ADDRESS, &server_node); if (st != IIIMF_STATUS_SUCCESS && st != IIIMF_STATUS_NO_ATTR_VALUE) goto error; st = iiimcf_attr_get_string_value(attr, IIIMCF_ATTR_SERVER_SERVICE, &service); if (st != IIIMF_STATUS_SUCCESS && st != IIIMF_STATUS_NO_ATTR_VALUE) goto error; if (server_node || service) { penv->pconf = iiimcf_client_config_new(server_node ? strdup(server_node) : NULL, service ? strdup(service) : NULL); if (!penv->pconf) goto memory_error; } st = iiimcf_attr_get_string_value(attr, IIIMCF_ATTR_USERNAME, &user_name); if (st == IIIMF_STATUS_SUCCESS) { penv->user_name = strdup(user_name); if (!penv->user_name) goto memory_error; } else if (st != IIIMF_STATUS_NO_ATTR_VALUE) { goto error; } { struct passwd *pwd; /* TODO! Use penv->user_name to check the home directory. */ if ((pwd = getpwuid(geteuid()))) { if (!penv->user_name) penv->user_name = strdup(pwd->pw_name); if (!penv->user_name) goto memory_error; penv->home_dir = strdup(pwd->pw_dir); if (!penv->home_dir) goto memory_error; endpwent(); } } /* We still fail to get user_name, set "Unknown" with force. */ if (!penv->user_name) { penv->user_name = strdup("Unknown"); if (!penv->user_name) goto memory_error; } st = iiimcf_attr_get_string_value(attr, IIIMCF_ATTR_PASSWORD, &password); if (st == IIIMF_STATUS_SUCCESS) { penv->password = strdup(password); if (!penv->password) goto memory_error; } else if (st == IIIMF_STATUS_NO_ATTR_VALUE) { st = iiimcf_client_auth_password(penv); if ((st != IIIMF_STATUS_SUCCESS) && (st != IIIMF_STATUS_CONFIG)) goto error; } else { goto error; } if (!server_node && !service) { st = iiimcf_client_environ_server(penv); if (st != IIIMF_STATUS_SUCCESS) { st = iiimcf_client_file_server(penv); if (st != IIIMF_STATUS_SUCCESS) { st = iiimcf_client_file_compat_server(penv); } } } if (!penv->pconf) { /* * we don't have any pconfiguration. * prepare default one. */ int node_len; char *tmp_node; /* * first try to /tmp/.iiimp-unix-${USERNAME}/ */ node_len = strlen("/tmp/.iiimp-unix-") + strlen(penv->user_name); tmp_node = malloc(node_len + 1); if (!tmp_node) goto memory_error; snprintf(tmp_node, node_len + 1, "/tmp/.iiimp-unix-%s", penv->user_name); tmp_node[node_len] = '\0'; if (IIIMF_STATUS_SUCCESS != dir_valid(tmp_node, geteuid())) { /* * try /tmp/.iiimp-unix-${USERNAME}-xxxxxxxx/ */ free(tmp_node); tmp_node = NULL; st = iiimcf_alternate_unix_domain_socket_file_dir(penv, &tmp_node); } if (NULL != tmp_node) { penv->pconf = iiimcf_client_config_new(tmp_node, NULL); if (!penv->pconf) { free(tmp_node); goto memory_error; } } /* * second try to $SOCKETDIR/.iiimp-unix/ */ tmp_node = strdup(SOCKETDIR "/.iiimp-unix"); if (!tmp_node) goto memory_error; pconf = iiimcf_client_config_new(tmp_node, NULL); if (NULL == pconf) { free(tmp_node); goto memory_error; } if (NULL == penv->pconf) { penv->pconf = pconf; } else { penv->pconf->next = pconf; } } st = iiimcf_attr_get_string_value(attr, IIIMCF_ATTR_CLIENT_TYPE, &clientname); if (st == IIIMF_STATUS_SUCCESS) { penv->type = strdup(clientname); } else if (st == IIIMF_STATUS_NO_ATTR_VALUE) { penv->type = strdup(CLIENT_TYPE); } else { goto error; } if (!penv->type) goto memory_error; st = iiimcf_attr_get_string_value(attr, IIIMCF_ATTR_CLIENT_X_DISPLAY_NAME, &x_display_name); if (st == IIIMF_STATUS_SUCCESS) { penv->X_display_name = strdup(x_display_name); if (!penv->X_display_name) goto memory_error; } else if (st != IIIMF_STATUS_NO_ATTR_VALUE) { goto error; } st = iiimcf_attr_get_string_value(attr, IIIMCF_ATTR_CLIENT_X_SERVER_VENDOR, &x_server_vendor); if (st == IIIMF_STATUS_SUCCESS) { penv->X_server_vendor = strdup(x_server_vendor); if (!penv->X_server_vendor) goto memory_error; } else if (st != IIIMF_STATUS_NO_ATTR_VALUE) { goto error; } { struct utsname name; if (-1 != uname(&name)) { penv->node = strdup(name.nodename); if (!penv->node) goto memory_error; penv->os_name = strdup(name.sysname); if (!penv->os_name) goto memory_error; penv->os_version = strdup(name.release); if (!penv->os_version) goto memory_error; } } st = iiimcf_client_os_arch(penv); if ((st != IIIMF_STATUS_SUCCESS) && (st != IIIMF_STATUS_CONFIG)) goto error; *ppenv = penv; return IIIMF_STATUS_SUCCESS; memory_error: st = IIIMF_STATUS_MALLOC; error: iiimcf_delete_client_env(penv); return st; } IIIMF_status iiimcf_delete_client_env( IIIMCF_client_env *penv ) { if (penv->user_name) free(penv->user_name); if (penv->password) free(penv->password); if (penv->home_dir) free(penv->home_dir); if (penv->node) free(penv->node); if (penv->type) free(penv->type); if (penv->os_name) free(penv->os_name); if (penv->os_arch) free(penv->os_arch); if (penv->os_version) free(penv->os_version); if (penv->X_display_name) free(penv->X_display_name); if (penv->X_server_vendor) free(penv->X_server_vendor); if (penv->pconf) iiimcf_client_config_free(penv->pconf); free(penv); return IIIMF_STATUS_SUCCESS; } IIIMF_status iiimcf_create_im_connect_message( IIIMCF_handle_rec *ph, IIIMP_message **ppmes ) { int len; char *user; IIIMF_status st; IIIMP_message *pmes; IIIMP_string *pim_user; IIIMCF_client_env *penv = ph->penv; len = strlen(penv->user_name); if (penv->node) len += strlen(penv->node); if (penv->password) len += strlen(penv->password); user = (char*) malloc(sizeof(char) * (len + 1 + 1 + 1)); /* for @, #, and \0. */ if (!user) return IIIMF_STATUS_MALLOC; strcpy(user, penv->user_name); if (penv->node) { strcat(user, "@"); strcat(user, penv->node); } if (penv->password) { strcat(user, "#"); strcat(user, penv->password); } st = iiimf_data_string_ascii_new(ph->data_s, user, &pim_user); free(user); if (st != IIIMF_STATUS_SUCCESS) return st; pmes = iiimp_connect_new(ph->data_s, pim_user, NULL); if (!pmes) { iiimp_string_delete(ph->data_s, pim_user); return IIIMF_STATUS_MALLOC; } *ppmes = pmes; return IIIMF_STATUS_SUCCESS; } IIIMF_status iiimcf_create_client_descriptor_message( IIIMCF_handle_rec *ph, IIIMP_message **ppmes ) { IIIMF_status st; IIIMCF_client_env *penv = ph->penv; IIIMP_message *pmes; IIIMP_imattribute *pimattr; IIIMP_client_descriptor *cdesc; IIIMP_string *type, *os_name, *os_arch, *os_ver; IIIMP_string *X_display_name, *X_server_vendor; pmes = NULL; pimattr = NULL; cdesc = NULL; type = os_name = os_arch = os_ver = NULL; X_display_name = X_server_vendor = NULL; st = iiimf_data_string_ascii_new(ph->data_s, penv->type, &type); if (st != IIIMF_STATUS_SUCCESS) goto error; st = iiimf_data_string_ascii_new(ph->data_s, penv->os_name, &os_name); if (st != IIIMF_STATUS_SUCCESS) goto error; st = iiimf_data_string_ascii_new(ph->data_s, penv->os_arch, &os_arch); if (st != IIIMF_STATUS_SUCCESS) goto error; st = iiimf_data_string_ascii_new(ph->data_s, penv->os_version, &os_ver); if (st != IIIMF_STATUS_SUCCESS) goto error; if (penv->X_display_name) { st = iiimf_data_string_ascii_new(ph->data_s, penv->X_display_name, &X_display_name); if (st != IIIMF_STATUS_SUCCESS) goto error; } if (penv->X_server_vendor) { st = iiimf_data_string_ascii_new(ph->data_s, penv->X_server_vendor, &X_server_vendor); if (st != IIIMF_STATUS_SUCCESS) goto error; } cdesc = iiimp_client_descriptor_new(ph->data_s, type, os_name, os_arch, os_ver, X_display_name, X_server_vendor); if (!cdesc) goto error; pimattr = iiimp_imattribute_client_descriptor_new(ph->data_s, IIIMP_IMATTRIBUTE_CLIENT_DESCRIPTOR, 0, cdesc); if (!pimattr) goto error; pmes = iiimp_setimvalues_new(ph->data_s, ph->im_id, pimattr); if (!pmes) goto error; *ppmes = pmes; return IIIMF_STATUS_SUCCESS; error: if (type) iiimp_string_delete(ph->data_s, type); if (os_name) iiimp_string_delete(ph->data_s, os_name); if (os_arch) iiimp_string_delete(ph->data_s, os_arch); if (os_ver) iiimp_string_delete(ph->data_s, os_ver); if (X_display_name) iiimp_string_delete(ph->data_s, X_display_name); if (X_server_vendor) iiimp_string_delete(ph->data_s, X_server_vendor); if (cdesc) iiimp_client_descriptor_delete(ph->data_s, cdesc); if (pimattr) iiimp_imattribute_delete(ph->data_s, pimattr); return IIIMF_STATUS_MALLOC; } /* Local Variables: */ /* c-file-style: "iiim-project" */ /* End: */