1 /**
2 * Copyright 2016-2017 Couchbase, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "couchbase.h"
18
19 #include <ext/standard/md5.h>
20
21 #define LOGARGS(lvl) LCB_LOG_##lvl, NULL, "pcbc/password_authenticator", __FILE__, __LINE__
22
23 zend_class_entry *pcbc_password_authenticator_ce;
24 extern zend_class_entry *pcbc_authenticator_ce;
25
26 /* {{{ proto void PasswordAuthenticator::__construct() */
PHP_METHOD(PasswordAuthenticator,__construct)27 PHP_METHOD(PasswordAuthenticator, __construct)
28 {
29 pcbc_password_authenticator_t *obj;
30 int rv;
31
32 rv = zend_parse_parameters_none();
33 if (rv == FAILURE) {
34 throw_pcbc_exception("Invalid arguments.", LCB_EINVAL);
35 RETURN_NULL();
36 }
37 obj = Z_PASSWORD_AUTHENTICATOR_OBJ_P(getThis());
38 obj->username = NULL;
39 obj->username_len = 0;
40 obj->password = NULL;
41 obj->password_len = 0;
42 }
43 /* }}} */
44
pcbc_password_authenticator_init(zval * return_value,char * username,int username_len,char * password,int password_len TSRMLS_DC)45 void pcbc_password_authenticator_init(zval *return_value, char *username, int username_len, char *password,
46 int password_len TSRMLS_DC)
47 {
48 pcbc_password_authenticator_t *obj;
49
50 object_init_ex(return_value, pcbc_password_authenticator_ce);
51 obj = Z_PASSWORD_AUTHENTICATOR_OBJ_P(return_value);
52 obj->username = estrndup(username, username_len);
53 obj->username_len = username_len;
54 obj->password = estrndup(password, password_len);
55 obj->password_len = password_len;
56 }
57
58 /* {{{ proto \Couchbase\PasswordAuthenticator PasswordAuthenticator::username(string $username)
59 */
PHP_METHOD(PasswordAuthenticator,username)60 PHP_METHOD(PasswordAuthenticator, username)
61 {
62 pcbc_password_authenticator_t *obj;
63 char *username = NULL;
64 pcbc_str_arg_size username_len;
65 int rv;
66
67 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &username, &username_len);
68 if (rv == FAILURE) {
69 RETURN_NULL();
70 }
71
72 obj = Z_PASSWORD_AUTHENTICATOR_OBJ_P(getThis());
73
74 if (obj->username) {
75 efree(obj->username);
76 }
77 obj->username_len = username_len;
78 obj->username = estrndup(username, username_len);
79
80 RETURN_ZVAL(getThis(), 1, 0);
81 } /* }}} */
82
83 /* {{{ proto \Couchbase\PasswordAuthenticator PasswordAuthenticator::password(string $password)
84 */
PHP_METHOD(PasswordAuthenticator,password)85 PHP_METHOD(PasswordAuthenticator, password)
86 {
87 pcbc_password_authenticator_t *obj;
88 char *password = NULL;
89 pcbc_str_arg_size password_len;
90 int rv;
91
92 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &password, &password_len);
93 if (rv == FAILURE) {
94 RETURN_NULL();
95 }
96
97 obj = Z_PASSWORD_AUTHENTICATOR_OBJ_P(getThis());
98
99 if (obj->password) {
100 efree(obj->password);
101 }
102 obj->password_len = password_len;
103 obj->password = estrndup(password, password_len);
104
105 RETURN_ZVAL(getThis(), 1, 0);
106 } /* }}} */
107
pcbc_generate_password_lcb_auth(pcbc_password_authenticator_t * auth,lcb_AUTHENTICATOR ** result,lcb_type_t type,const char * name,const char * password,char ** hash TSRMLS_DC)108 void pcbc_generate_password_lcb_auth(pcbc_password_authenticator_t *auth, lcb_AUTHENTICATOR **result, lcb_type_t type,
109 const char *name, const char *password, char **hash TSRMLS_DC)
110 {
111 PHP_MD5_CTX md5;
112 unsigned char digest[16];
113
114 *result = lcbauth_new();
115 lcbauth_set_mode(*result, LCBAUTH_MODE_RBAC);
116 PHP_MD5Init(&md5);
117
118 if (name && password) {
119 lcbauth_add_pass(*result, name, password, LCBAUTH_F_CLUSTER);
120 PHP_MD5Update(&md5, "rbac-extra", sizeof("rbac-extra"));
121 PHP_MD5Update(&md5, name, strlen(name));
122 PHP_MD5Update(&md5, password, strlen(password));
123 } else {
124 lcbauth_add_pass(*result, auth->username, auth->password, LCBAUTH_F_CLUSTER);
125 PHP_MD5Update(&md5, "rbac", sizeof("rbac"));
126 PHP_MD5Update(&md5, auth->username, auth->username_len);
127 PHP_MD5Update(&md5, auth->password, auth->password_len);
128 }
129 PHP_MD5Final(digest, &md5);
130 *hash = ecalloc(sizeof(char), 33);
131 make_digest(*hash, digest);
132 }
133
134 ZEND_BEGIN_ARG_INFO_EX(ai_PasswordAuthenticator_none, 0, 0, 0)
135 ZEND_END_ARG_INFO()
136
137 ZEND_BEGIN_ARG_INFO_EX(ai_PasswordAuthenticator_username, 0, 0, 1)
138 ZEND_ARG_INFO(0, username)
139 ZEND_END_ARG_INFO()
140
141 ZEND_BEGIN_ARG_INFO_EX(ai_PasswordAuthenticator_password, 0, 0, 2)
142 ZEND_ARG_INFO(0, password)
143 ZEND_END_ARG_INFO()
144
145 // clang-format off
146 zend_function_entry password_authenticator_methods[] = {
147 PHP_ME(PasswordAuthenticator, __construct, ai_PasswordAuthenticator_none, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
148 PHP_ME(PasswordAuthenticator, username, ai_PasswordAuthenticator_username, ZEND_ACC_PUBLIC)
149 PHP_ME(PasswordAuthenticator, password, ai_PasswordAuthenticator_password, ZEND_ACC_PUBLIC)
150 PHP_FE_END
151 };
152 // clang-format on
153
154 zend_object_handlers password_authenticator_handlers;
155
password_authenticator_free_object(pcbc_free_object_arg * object TSRMLS_DC)156 static void password_authenticator_free_object(pcbc_free_object_arg *object TSRMLS_DC) /* {{{ */
157 {
158 pcbc_password_authenticator_t *obj = Z_PASSWORD_AUTHENTICATOR_OBJ(object);
159
160 if (obj->username != NULL) {
161 efree(obj->username);
162 }
163 if (obj->password != NULL) {
164 efree(obj->password);
165 }
166
167 zend_object_std_dtor(&obj->std TSRMLS_CC);
168 #if PHP_VERSION_ID < 70000
169 efree(obj);
170 #endif
171 } /* }}} */
172
authenticator_create_object(zend_class_entry * class_type TSRMLS_DC)173 static pcbc_create_object_retval authenticator_create_object(zend_class_entry *class_type TSRMLS_DC)
174 {
175 pcbc_password_authenticator_t *obj = NULL;
176
177 obj = PCBC_ALLOC_OBJECT_T(pcbc_password_authenticator_t, class_type);
178
179 zend_object_std_init(&obj->std, class_type TSRMLS_CC);
180 object_properties_init(&obj->std, class_type);
181
182 #if PHP_VERSION_ID >= 70000
183 obj->std.handlers = &password_authenticator_handlers;
184 return &obj->std;
185 #else
186 {
187 zend_object_value ret;
188 ret.handle = zend_objects_store_put(obj, (zend_objects_store_dtor_t)zend_objects_destroy_object,
189 password_authenticator_free_object, NULL TSRMLS_CC);
190 ret.handlers = &password_authenticator_handlers;
191 return ret;
192 }
193 #endif
194 }
195
pcbc_password_authenticator_get_debug_info(zval * object,int * is_temp TSRMLS_DC)196 static HashTable *pcbc_password_authenticator_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
197 {
198 pcbc_password_authenticator_t *obj = NULL;
199 #if PHP_VERSION_ID >= 70000
200 zval retval;
201 #else
202 zval retval = zval_used_for_init;
203 #endif
204
205 *is_temp = 1;
206 obj = Z_PASSWORD_AUTHENTICATOR_OBJ_P(object);
207
208 array_init(&retval);
209 if (obj->username) {
210 ADD_ASSOC_STRING(&retval, "username", obj->username);
211 }
212 return Z_ARRVAL(retval);
213 } /* }}} */
214
PHP_MINIT_FUNCTION(PasswordAuthenticator)215 PHP_MINIT_FUNCTION(PasswordAuthenticator)
216 {
217 zend_class_entry ce;
218
219 INIT_NS_CLASS_ENTRY(ce, "Couchbase", "PasswordAuthenticator", password_authenticator_methods);
220 pcbc_password_authenticator_ce = zend_register_internal_class(&ce TSRMLS_CC);
221 pcbc_password_authenticator_ce->create_object = authenticator_create_object;
222 PCBC_CE_DISABLE_SERIALIZATION(pcbc_password_authenticator_ce);
223
224 zend_class_implements(pcbc_password_authenticator_ce TSRMLS_CC, 1, pcbc_authenticator_ce);
225
226 memcpy(&password_authenticator_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
227 password_authenticator_handlers.get_debug_info = pcbc_password_authenticator_get_debug_info;
228 #if PHP_VERSION_ID >= 70000
229 password_authenticator_handlers.free_obj = password_authenticator_free_object;
230 password_authenticator_handlers.offset = XtOffsetOf(pcbc_password_authenticator_t, std);
231 #endif
232
233 zend_register_class_alias("\\CouchbaseAuthenticator", pcbc_password_authenticator_ce);
234 return SUCCESS;
235 }
236