1 /* cvm/client.c - CVM client library
2 * Copyright (C) 2010 Bruce Guenter <bruce@untroubled.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 #include <sys/types.h>
19 #include <netdb.h>
20 #include <signal.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/wait.h>
24 #include <unistd.h>
25
26 #include <bglibs/sysdeps.h>
27 #include <bglibs/socket.h>
28
29 #include "v1client.h"
30 #include "protocol.h"
31
32 const char* cvm_client_account_split_chars = "@";
33
34 static struct cvm_packet request;
35 static struct cvm_packet response;
36
37 /* Packet management code ****************************************************/
parse_packet(struct cvm_packet * p)38 static int parse_packet(struct cvm_packet* p)
39 {
40 if (p->data[0] != 0)
41 return p->data[0];
42 if (p->length < 3
43 || p->data[p->length-1] != 0
44 || p->data[p->length-2] != 0)
45 return CVME_BAD_MODDATA;
46 if (cvm_client_fact_str(CVM_FACT_USERNAME, &cvm_fact_username) ||
47 cvm_client_fact_uint(CVM_FACT_USERID, &cvm_fact_userid) ||
48 cvm_client_fact_uint(CVM_FACT_GROUPID, &cvm_fact_groupid) ||
49 cvm_client_fact_str(CVM_FACT_DIRECTORY, &cvm_fact_directory))
50 return CVME_BAD_MODDATA;
51 cvm_client_fact_str(CVM_FACT_SHELL, &cvm_fact_shell);
52 cvm_client_fact_str(CVM_FACT_REALNAME, &cvm_fact_realname);
53 cvm_client_fact_str(CVM_FACT_GROUPNAME, &cvm_fact_groupname);
54 cvm_client_fact_str(CVM_FACT_SYS_USERNAME, &cvm_fact_sys_username);
55 cvm_client_fact_str(CVM_FACT_SYS_DIRECTORY, &cvm_fact_sys_directory);
56 cvm_client_fact_str(CVM_FACT_DOMAIN, &cvm_fact_domain);
57 cvm_client_fact_str(CVM_FACT_MAILBOX, &cvm_fact_mailbox);
58 return 0;
59 }
60
packet_add(struct cvm_packet * p,const char * str,unsigned len)61 static int packet_add(struct cvm_packet* p,
62 const char* str, unsigned len)
63 {
64 unsigned char* ptr;
65 if (p->length + len + 1 >= CVM_BUFSIZE-1)
66 return 0;
67 ptr = p->data + p->length;
68 memcpy(ptr, str, len);
69 ptr[len] = 0;
70 p->length += len + 1;
71 return 1;
72 }
73
build_packet(struct cvm_packet * p,const char * account,const char * domain,const char ** credentials,int parse_domain)74 static unsigned build_packet(struct cvm_packet* p,
75 const char* account, const char* domain,
76 const char** credentials, int parse_domain)
77 {
78 unsigned i;
79 unsigned actlen;
80
81 p->data[0] = CVM1_PROTOCOL;
82 p->length = 1;
83
84 actlen = strlen(account);
85 if (parse_domain) {
86 const char* sc;
87 if ((sc = getenv("CVM_ACCOUNT_SPLIT_CHARS")) == 0)
88 sc = cvm_client_account_split_chars;
89 i = strlen(account);
90 while (i-- > 0) {
91 if (strchr(sc, account[i]) != 0) {
92 domain = account + i + 1;
93 actlen = i;
94 break;
95 }
96 }
97 }
98
99 if (!packet_add(p, account, actlen)) return 0;
100 if (!packet_add(p, domain, strlen(domain))) return 0;
101
102 for (i = 0; credentials[i] != 0; i++)
103 if (!packet_add(p, credentials[i], strlen(credentials[i])))
104 return 0;
105
106 p->data[p->length++] = 0;
107 return 1;
108 }
109
cvm_client_fact_str(unsigned number,const char ** data)110 int cvm_client_fact_str(unsigned number, const char** data)
111 {
112 static unsigned char* ptr = 0;
113 static unsigned last_number = -1;
114
115 if (!ptr || number != last_number)
116 ptr = response.data+1;
117 last_number = number;
118
119 while (*ptr) {
120 unsigned char* tmp = ptr;
121 ptr += strlen((char*)ptr) + 1;
122 if (*tmp == number) {
123 *data = (char*)tmp + 1;
124 return 0;
125 }
126 }
127 return CVME_NOFACT;
128 }
129
cvm_client_fact_uint(unsigned number,unsigned long * data)130 int cvm_client_fact_uint(unsigned number, unsigned long* data)
131 {
132 const char* str;
133 unsigned long i;
134 int err;
135
136 if ((err = cvm_client_fact_str(number, &str)) != 0) return err;
137
138 for (i = 0; *str >= '0' && *str <= '9'; ++str) {
139 unsigned long tmp = i;
140 i = (i * 10) + (*str - '0');
141 if (i < tmp)
142 return CVME_BAD_MODDATA;
143 }
144 if (*str)
145 return CVME_BAD_MODDATA;
146 *data = i;
147 return 0;
148 }
149
150 /* Top-level wrapper *********************************************************/
cvm_client_authenticate(const char * module,const char * account,const char * domain,const char ** credentials,int parse_domain)151 int cvm_client_authenticate(const char* module, const char* account,
152 const char* domain, const char** credentials,
153 int parse_domain)
154 {
155 int result;
156 void (*oldsig)(int);
157 if (domain == 0) domain = "";
158 if (!build_packet(&request, account, domain, credentials, parse_domain))
159 return CVME_GENERAL;
160
161 oldsig = signal(SIGPIPE, SIG_IGN);
162 if (!memcmp(module, "cvm-udp:", 8))
163 result = cvm_xfer_udp_packets(module+8, &request, &response);
164 else if (!memcmp(module, "cvm-local:", 10))
165 result = cvm_xfer_local_packets(module+10, &request, &response);
166 else {
167 if (!memcmp(module, "cvm-command:", 12)) module += 12;
168 result = cvm_xfer_command_packets(module, &request, &response);
169 }
170 signal(SIGPIPE, oldsig);
171 if (result != 0) return result;
172 return parse_packet(&response);
173 }
174