Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Samba utility functions
4 : Copyright (C) Andrew Bartlett 2011
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "replace.h"
21 : #include "lib/util/debug.h"
22 : #include "lib/util/fault.h"
23 : #include "lib/util/server_id.h"
24 : #include "lib/util/byteorder.h"
25 : #include "librpc/gen_ndr/server_id.h"
26 :
27 99460 : bool server_id_same_process(const struct server_id *p1,
28 : const struct server_id *p2)
29 : {
30 99460 : return ((p1->pid == p2->pid) && (p1->vnn == p2->vnn));
31 : }
32 :
33 3017088 : int server_id_cmp(const struct server_id *p1, const struct server_id *p2)
34 : {
35 3017088 : if (p1->vnn != p2->vnn) {
36 1217 : return (p1->vnn < p2->vnn) ? -1 : 1;
37 : }
38 3015871 : if (p1->pid != p2->pid) {
39 1438664 : return (p1->pid < p2->pid) ? -1 : 1;
40 : }
41 1577207 : if (p1->task_id != p2->task_id) {
42 0 : return (p1->task_id < p2->task_id) ? -1 : 1;
43 : }
44 1577207 : if (p1->unique_id != p2->unique_id) {
45 0 : return (p1->unique_id < p2->unique_id) ? -1 : 1;
46 : }
47 1573956 : return 0;
48 : }
49 :
50 2517720 : bool server_id_equal(const struct server_id *p1, const struct server_id *p2)
51 : {
52 2517720 : int cmp = server_id_cmp(p1, p2);
53 2517720 : return (cmp == 0);
54 : }
55 :
56 261772 : char *server_id_str_buf(struct server_id id, struct server_id_buf *dst)
57 : {
58 261772 : if (server_id_is_disconnected(&id)) {
59 0 : strlcpy(dst->buf, "disconnected", sizeof(dst->buf));
60 261772 : } else if ((id.vnn == NONCLUSTER_VNN) && (id.task_id == 0)) {
61 88445 : snprintf(dst->buf, sizeof(dst->buf), "%llu",
62 84177 : (unsigned long long)id.pid);
63 177595 : } else if (id.vnn == NONCLUSTER_VNN) {
64 181863 : snprintf(dst->buf, sizeof(dst->buf), "%llu.%u",
65 177595 : (unsigned long long)id.pid, (unsigned)id.task_id);
66 0 : } else if (id.task_id == 0) {
67 4268 : snprintf(dst->buf, sizeof(dst->buf), "%u:%llu",
68 0 : (unsigned)id.vnn, (unsigned long long)id.pid);
69 : } else {
70 4268 : snprintf(dst->buf, sizeof(dst->buf), "%u:%llu.%u",
71 0 : (unsigned)id.vnn,
72 0 : (unsigned long long)id.pid,
73 0 : (unsigned)id.task_id);
74 : }
75 261772 : return dst->buf;
76 : }
77 :
78 129368 : size_t server_id_str_buf_unique(struct server_id id, char *buf, size_t buflen)
79 : {
80 920 : struct server_id_buf idbuf;
81 920 : char unique_buf[21]; /* 2^64 is 18446744073709551616, 20 chars */
82 920 : size_t idlen, unique_len, needed;
83 :
84 129368 : server_id_str_buf(id, &idbuf);
85 :
86 129368 : idlen = strlen(idbuf.buf);
87 129368 : unique_len = snprintf(unique_buf, sizeof(unique_buf), "%"PRIu64,
88 : id.unique_id);
89 129368 : needed = idlen + unique_len + 2;
90 :
91 129368 : if (buflen >= needed) {
92 64684 : memcpy(buf, idbuf.buf, idlen);
93 64684 : buf[idlen] = '/';
94 64684 : memcpy(buf + idlen + 1, unique_buf, unique_len+1);
95 : }
96 :
97 129368 : return needed;
98 : }
99 :
100 59227 : struct server_id server_id_from_string(uint32_t local_vnn,
101 : const char *pid_string)
102 : {
103 59227 : struct server_id templ = {
104 : .vnn = NONCLUSTER_VNN, .pid = UINT64_MAX
105 : };
106 1810 : struct server_id result;
107 1810 : int ret;
108 :
109 : /*
110 : * We accept various forms with 1, 2 or 3 component forms
111 : * because the server_id_str_buf() can print different forms, and
112 : * we want backwards compatibility for scripts that may call
113 : * smbclient.
114 : */
115 :
116 59227 : result = templ;
117 59227 : ret = sscanf(pid_string, "%"SCNu32":%"SCNu64".%"SCNu32"/%"SCNu64,
118 : &result.vnn, &result.pid, &result.task_id,
119 : &result.unique_id);
120 59227 : if (ret == 4) {
121 0 : return result;
122 : }
123 :
124 59227 : result = templ;
125 59227 : ret = sscanf(pid_string, "%"SCNu32":%"SCNu64".%"SCNu32,
126 : &result.vnn, &result.pid, &result.task_id);
127 59227 : if (ret == 3) {
128 0 : return result;
129 : }
130 :
131 59227 : result = templ;
132 59227 : ret = sscanf(pid_string, "%"SCNu32":%"SCNu64"/%"SCNu64,
133 : &result.vnn, &result.pid, &result.unique_id);
134 59227 : if (ret == 3) {
135 0 : return result;
136 : }
137 :
138 59227 : result = templ;
139 59227 : ret = sscanf(pid_string, "%"SCNu32":%"SCNu64,
140 : &result.vnn, &result.pid);
141 59227 : if (ret == 2) {
142 4 : return result;
143 : }
144 :
145 59223 : result = templ;
146 59223 : ret = sscanf(pid_string, "%"SCNu64".%"SCNu32"/%"SCNu64,
147 : &result.pid, &result.task_id, &result.unique_id);
148 59223 : if (ret == 3) {
149 4137 : result.vnn = local_vnn;
150 4137 : return result;
151 : }
152 :
153 55086 : result = templ;
154 55086 : ret = sscanf(pid_string, "%"SCNu64".%"SCNu32,
155 : &result.pid, &result.task_id);
156 55086 : if (ret == 2) {
157 0 : result.vnn = local_vnn;
158 0 : return result;
159 : }
160 :
161 55086 : result = templ;
162 55086 : ret = sscanf(pid_string, "%"SCNu64"/%"SCNu64,
163 : &result.pid, &result.unique_id);
164 55086 : if (ret == 2) {
165 54882 : result.vnn = local_vnn;
166 54882 : return result;
167 : }
168 :
169 204 : result = templ;
170 204 : ret = sscanf(pid_string, "%"SCNu64, &result.pid);
171 204 : if (ret == 1) {
172 154 : result.vnn = local_vnn;
173 154 : return result;
174 : }
175 :
176 50 : if (strcmp(pid_string, "disconnected") == 0) {
177 0 : server_id_set_disconnected(&result);
178 0 : return result;
179 : }
180 :
181 50 : return templ;
182 : }
183 :
184 : /**
185 : * Set the serverid to the special value that represents a disconnected
186 : * client for (e.g.) durable handles.
187 : */
188 1468136 : void server_id_set_disconnected(struct server_id *id)
189 : {
190 1468136 : *id = (struct server_id) {
191 : .pid = UINT64_MAX,
192 : .task_id = UINT32_MAX,
193 : .vnn = NONCLUSTER_VNN,
194 : .unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY,
195 : };
196 1468136 : }
197 :
198 : /**
199 : * check whether a serverid is the special placeholder for
200 : * a disconnected client
201 : */
202 873679 : bool server_id_is_disconnected(const struct server_id *id)
203 : {
204 6004 : struct server_id dis;
205 :
206 873679 : SMB_ASSERT(id != NULL);
207 :
208 873679 : server_id_set_disconnected(&dis);
209 :
210 873679 : return server_id_equal(id, &dis);
211 : }
212 :
213 2228025 : void server_id_put(uint8_t buf[SERVER_ID_BUF_LENGTH],
214 : const struct server_id id)
215 : {
216 2228025 : SBVAL(buf, 0, id.pid);
217 2228025 : SIVAL(buf, 8, id.task_id);
218 2228025 : SIVAL(buf, 12, id.vnn);
219 2228025 : SBVAL(buf, 16, id.unique_id);
220 2228025 : }
221 :
222 2392889 : void server_id_get(struct server_id *id,
223 : const uint8_t buf[SERVER_ID_BUF_LENGTH])
224 : {
225 2392889 : id->pid = BVAL(buf, 0);
226 2392889 : id->task_id = IVAL(buf, 8);
227 2392889 : id->vnn = IVAL(buf, 12);
228 2392889 : id->unique_id = BVAL(buf, 16);
229 2392889 : }
|